home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 38 / Amiga Format CD38 (1999-03-15)(Future Publishing)(GB)(Track 1 of 3)[!][issue 1999-04].iso / -in_the_mag- / cuckoo99 / scsiutil / scsiutil.c < prev    next >
C/C++ Source or Header  |  1999-02-05  |  72KB  |  2,730 lines

  1. /*
  2.  *****    SCSIutil
  3.  *
  4.  *    A utility to do some low-level operations to a SCSI disk, e.g.
  5.  *
  6.  *        - start/stop motor
  7.  *        - read sectors
  8.  *        - read disk capacity info
  9.  *        - get inquiry info (manufacturers name etc)
  10.  *        - seek to a sector's cylinder (use to park heads)
  11.  *        - play audio tracks of a CD-DA
  12.  *        - eject/insert a medium
  13.  *        - read digital data off audio CDs (with Sony 8003 = Apple CD300
  14.  *          and Toshiba 3401)
  15.  *        - set output volume of a CD-ROM drive
  16.  *
  17.  *    NOTE:  this program is based on SCSI information taken from
  18.  *           the accompanying documentation of a NEC D3841 SCSI disk.
  19.  *           I don't know the extent to which SCSI standards are
  20.  *           supported by that disk.
  21.  *
  22.  *           These commands work on the above disk. But a seek to
  23.  *           sector -1 (park on the NEC disk) fails on my Quantum 105.D
  24.  *
  25.  *    Program returns:
  26.  *    1 - init didn't work (maybe allocmem failed, etc.)
  27.  *    2 - wrong parameter count
  28.  *    3 - wrong parameter
  29.  *
  30.  *****    Written by Gary Duncan
  31.  *
  32.  *    Bug reports etc via e-mail to gduncan@philips.oz.au) , or mail to
  33.  *
  34.  *    Gary Duncan
  35.  *    Philips PTS
  36.  *      23 Lakeside Dr
  37.  *    Tally-Ho Technology Park
  38.  *    Burwood East Vic 3151
  39.  *    Australia
  40.  *
  41.  * New features and rewrites by:
  42.  *
  43.  *    The Software Brewery
  44.  *    Heiko Rath
  45.  *    Raiffeisenstr.10a
  46.  *    D-64331 Weiterstadt
  47.  *    Germany
  48.  *
  49.  *    EMail: hr@brewhr.swb.de
  50.  *
  51.  *****    Freely distributable for non-commercial purposes
  52.  *
  53.  *    Compiles under Lattice 6.50
  54.  *    - needs AmigaDos 2.0  #includes
  55.  *
  56.  ***** Thanks to Markus Illenseer for some beta-testing.
  57.  *
  58.  *****    Function List :-
  59.  *
  60.  *    breakcheck()        by GD, modified by <HR>
  61.  *    __chkabort()        by <HR>
  62.  *    DoScsiCmd ()        by <HR>
  63.  *    err_str()        by GD
  64.  *    gcomp()            by GD
  65.  *    finddrivebrand()    by <HR>
  66.  *    GetDevName()        by GD
  67.  *    id2string ()        by <HR>
  68.  *    init ()            by GD, modified by <HR>
  69.  *    inquiry()        by GD, modified by <HR>
  70.  *    medium_removal()    by <HR>
  71.  *    mode_sense()        by <HR>
  72.  *    motor ()        by GD, modified by <HR>
  73.  *    play_audio ()        by <HR>
  74.  *    rawahexasciioutput()    by <HR>
  75.  *    rawhexoutput()        by <HR>
  76.  *    read_capacity()        by GD, modified by <HR>
  77.  *    read_cdblockheader()    by <HR>
  78.  *    read_cddaasync()    by <HR>
  79.  *    read_sec ()        by GD, modified by <HR>
  80.  *    read_sec_scsi ()    by GD, modified by <HR>
  81.  *    read_subchannel()    by <HR>
  82.  *    read_toc ()        by <HR>
  83.  *    seek ()            by GD, modified by <HR>
  84.  *    SendScsiCmd()        by <HR>
  85.  *    sense_errs()        by GD
  86.  *    set_volume()        by <HR>
  87.  *    usage()            by GD, modified by <HR>
  88.  *    WaitScsiCmd()        by <HR>
  89.  *
  90.  */
  91.  
  92. #define VERSION "2.02"
  93.  
  94. /*
  95.  **** Includes
  96.  */
  97. #include <stdio.h>
  98. #include <string.h>
  99. #include <ctype.h>
  100. #include <exec/types.h>
  101. #include <exec/io.h>
  102. #include <exec/execbase.h>
  103. #include <exec/nodes.h>
  104. #include <exec/memory.h>
  105. #include <devices/trackdisk.h>
  106. #include <devices/scsidisk.h>
  107. #include <libraries/dos.h>
  108. #ifdef __SASC
  109. #include <proto/all.h>
  110. #else
  111. #include <clib/alib_protos.h>
  112. #include <clib/exec_protos.h>
  113. /* non-ANSI C macro isascii() */
  114. #define isascii(a) (((a) & 0x80) == 0)
  115. #endif
  116. #include "scsi_priv.h"
  117.  
  118. /*
  119.  * string for AmigaDOS Version Command 
  120.  */
  121. char A_vers[] = "\0$VER: SCSIutil " VERSION " (" __DATE__ " " __TIME__ ")";
  122.  
  123. /*
  124.  **** Global variables
  125.  */
  126. UBYTE *ip_buf = NULL;
  127. UBYTE *scsi_data = NULL;
  128. UBYTE *toc_buf = NULL;
  129.  
  130. UBYTE *dev = "";
  131.  
  132. int scsi_id = -1;        /* ID of the SCSI device to send commands to */
  133. UBYTE *pname;
  134. UBYTE buffer[LINE_BUF];
  135. int secno = -1;
  136. DRIVETYPE whatdrive = UNKNOWN;    /* what CD-ROM brand */
  137.  
  138. UBYTE *cdda_buf[NDBLBUF];
  139. MSGPORT *mp_ptr[NDBLBUF];
  140. IOSTDREQ *io_ptr[NDBLBUF];
  141. SCSICMD scsi_cmd[NDBLBUF];
  142. UBYTE *scsi_sense[NDBLBUF];
  143. UBYTE scsi_status[NDBLBUF];
  144. BYTE *mono_buf[NDBLBUF];
  145.  
  146. #ifdef USE8SVX
  147. BYTE write8svx = FALSE;        /* convert to 8SVX */
  148. #endif    /* USE8SVX */
  149.  
  150. /*
  151.  **** Function descr.
  152.  */
  153. int breakcheck (void);
  154. int DoScsiCmd (UBYTE * data, int datasize, UBYTE * cmd, int cmdsize, UBYTE flags);
  155. UBYTE *err_str (int err);
  156. void exit (int status);
  157. void finddrivebrand (void);
  158. int gcomp (char *p1, char *p2, int len);
  159. UBYTE *GetDevName (char *grep);
  160. UBYTE *id2string (int id, IDTOSTRING * idtable);
  161. BOOLEAN init (void);
  162. void inquiry (BOOLEAN parsedoutput);
  163. void medium_removal(BOOLEAN lock);
  164. void mode_sense (BOOLEAN parsed, UBYTE control, UBYTE page);
  165. void motor (int motorstatus);
  166. void play_audio (int starttrack, int startindex, int endtrack, int endindex);
  167. void rawhexasciioutput (UBYTE *p, UWORD numbytes, UBYTE leadspace);
  168. void rawhexoutput (UBYTE *p, UWORD numbytes);
  169. void read_capacity (BOOLEAN parsed);
  170. void read_cdblockheader (BOOLEAN parsed, ULONG block);
  171. #ifdef _DCC
  172. __stkargs
  173. #endif
  174. void read_cddaasync (ULONG startblock, ULONG numblocks, BYTE
  175.              whichchannel, BYTE use16bit, unsigned int subcode);
  176. void read_sec (void);
  177. void read_sec_scsi (void);
  178. void read_subchannel (BOOLEAN parsed, UBYTE subchannel, UBYTE subchannelformat, UBYTE track);
  179. void read_toc (int toclong);
  180. void seek (void);
  181. UBYTE *sense_errs (int req, int err);
  182. void set_volume (int vol0, int vol1, int vol2, int vol3);
  183. void usage (void);
  184.  
  185. int WaitScsiCmd (int req);
  186. void SendScsiCmd (int req, UBYTE * data, int datasize, UBYTE * cmd, int cmdsize, UBYTE flags);
  187.  
  188. #ifdef __SASC
  189. void __regargs __chkabort (void);
  190. #endif    /* __SASC */
  191. #ifdef _DCC
  192. #include <stdlib.h>
  193. typedef int (*brkfuncptr)();
  194. int brkhandler() { return(0); }
  195. #endif
  196.  
  197.  
  198.  
  199. /*********************************************************************
  200.  *
  201.  *    main
  202.  *
  203.  *
  204.  */
  205.  
  206. int
  207. main (int argc, char **argv)
  208. {
  209.   UBYTE *p;
  210.   int j = 0, i = 0;
  211.   int returnvalue = 0;
  212.  
  213. #ifdef _DCC
  214.   int (*oldbrkhandler)() = onbreak(brkhandler);
  215. #endif
  216.   if (argc == 1)
  217.     {
  218.       usage ();
  219.       exit (1);
  220.     }
  221.  
  222.   /*
  223.    *      see if a SCSI.device specified
  224.    */
  225.   if (strncmp (argv[1], "-d", 2) == 0)
  226.     {
  227.       j = 1;
  228.       dev = argv[1] + 2;
  229.     }
  230.   else if ((dev = GetDevName (SCSI_STRING)) == NULL)
  231.     {
  232.       fprintf (stderr, "Error : no *scsi*.device in device list\n");
  233.       exit (1);
  234.     }
  235.   pname = argv[0];
  236.   if (argc < (j + 2))
  237.     {
  238.       usage ();            /* help inquiry */
  239.       exit (1);
  240.     }
  241.  
  242.   if (argc < (j + 3))
  243.     {
  244.       fprintf (stderr, "Error : Not enough params\n");
  245.       exit (1);
  246.     }
  247.  
  248.   /*
  249.    *    pick up SCSI id ; do a rough check
  250.    */
  251.   if (sscanf (argv[j + 1], "%d", &scsi_id) != 1 || scsi_id < 0)
  252.     {
  253.       fprintf (stderr, "Error : Bad scsi id\n");
  254.       exit (1);
  255.     }
  256.  
  257.   if (*(p = argv[j + 2]) != '-')
  258.     {
  259.       fprintf (stderr, "Error : bad option\n");
  260.       exit (1);
  261.     }
  262.  
  263.   /*
  264.    *    now set up structures etc for SCSI xfer
  265.    */
  266.   if (init () == FALSE)
  267.     {
  268.       returnvalue = 1;
  269.       goto error;
  270.     }
  271.  
  272.  
  273.   /*
  274.    **********************    now examine the options
  275.    */
  276.   if (argc == (j + 3))
  277.     /* commands without parameter */
  278.     {
  279.       switch (*++p)
  280.     {
  281.       /*
  282.            ****     read capacity
  283.            */
  284.     case 'c':
  285.       if (*++p == 'r')
  286.         {
  287.               read_capacity (FALSE);    /* output raw data */
  288.             }
  289.           else
  290.             {
  291.               read_capacity (TRUE);    /* output parsed data */
  292.             }
  293.       break;
  294.  
  295.       /*
  296.            ****     inquiry (raw)
  297.            */
  298.     case 'i':
  299.       if (*++p == 'r')
  300.         {
  301.               inquiry (FALSE);        /* output raw data */
  302.             }
  303.           else
  304.             {
  305.               inquiry (TRUE);        /* output parsed data */
  306.             }
  307.       break;
  308.  
  309.       /*
  310.            ****     read TOC
  311.            */
  312.     case 't':
  313.       if (*(p+1) == 'r')
  314.         {
  315.           read_toc(0);    /* output raw data */
  316.         }
  317.       else if (*(p+1) == 'l')
  318.         {
  319.           read_toc(2);    /* output long form */
  320.         }
  321.       else
  322.         {
  323.               read_toc(1);    /* output short form */
  324.         }
  325.       break;
  326.  
  327.       /*
  328.            ****     show volume settings
  329.            */
  330.     case 'v':
  331.       set_volume (-1, -1, -1, -1);
  332.       break;
  333.  
  334.     default:
  335.       fprintf (stderr, "Error : bad option\n");
  336.       returnvalue = 3;
  337.     }
  338.     }
  339.   else if (argc == (j + 4))
  340.     /* commands with one parameter */
  341.     {
  342.       switch (*++p)
  343.     {
  344.       /*
  345.            ****     change medium
  346.            */
  347.     case 'e':
  348.       {
  349.         int eject = -1;
  350.             
  351.             if (sscanf (argv[j + 3], "%d", &eject) != 1
  352.                 || ((eject != 0) && (eject != 1)))
  353.               {
  354.                 fprintf (stderr, "Error : eject/load control must be 0 or 1\n");
  355.                 returnvalue = 3;
  356.               }
  357.             else
  358.               {
  359.                 motor ((eject | 2));    /* eject/insert */
  360.               }
  361.       }
  362.       break;
  363.  
  364.       /*
  365.            ****     read CD-ROM data block address header
  366.            */
  367.     case 'h':
  368.       {
  369.         ULONG block;
  370.  
  371.         if (sscanf (argv[j + 3], "%lu", &block) != 1)
  372.           {
  373.             fprintf (stderr, "Error : Bad block no\n");
  374.             returnvalue = 3;
  375.           }
  376.         else
  377.           {
  378.             if (*++p == 'r')
  379.               {
  380.                 read_cdblockheader (FALSE, block);
  381.               }
  382.             else
  383.               {
  384.                 read_cdblockheader (TRUE, block);
  385.               }
  386.           }
  387.       }
  388.       break;
  389.  
  390.       /*
  391.            ****     prevent/allow medium removal
  392.            */
  393.     case 'l':
  394.       {
  395.         int lock = -1;
  396.  
  397.             if (sscanf (argv[j + 3], "%d", &lock) != 1
  398.                || ((lock != 0) && (lock != 1)) )
  399.               {
  400.                 fprintf (stderr, "Error : Medium removal control must be 0 or 1\n");
  401.                 returnvalue = 3;
  402.               }
  403.             else
  404.               {
  405.                 medium_removal (lock);    /* prevent/allow medium removal */
  406.               }
  407.       }
  408.       break;
  409.  
  410.       /*
  411.            ****     stop/start motor
  412.            */
  413.     case 'm':
  414.       {
  415.         int motoronoff = -1;
  416.  
  417.             if (sscanf (argv[j + 3], "%d", &motoronoff) != 1
  418.                || ((motoronoff != 0) && (motoronoff != 1)) )
  419.               {
  420.                 fprintf (stderr, "Error : motor control must be 0 or 1\n");
  421.                 returnvalue = 3;
  422.               }
  423.             else
  424.               {
  425.                 motor (motoronoff);    /* turn on/off motor */
  426.               }
  427.       }
  428.       break;
  429.  
  430.       /*
  431.            ****     read sectors
  432.            */
  433.  
  434.     case 'r':
  435.       /*
  436.            *        get sector #
  437.            */
  438.       if (sscanf (argv[j + 3], "%d", &secno) != 1)
  439.         {
  440.           fprintf (stderr, "Error : Bad sec no\n");
  441.           returnvalue = 3;
  442.         }
  443.       else
  444.         {
  445.           if (*++p == 't')
  446.             {
  447.                   read_sec ();    /* read sector with trackdisk.device */
  448.             }
  449.           else
  450.             {
  451.                   read_sec_scsi ();    /* read sector with scsi */
  452.             }
  453.         }
  454.       break;
  455.  
  456.       /*
  457.            ****     seek to cylinder containing secno
  458.            */
  459.     case 's':
  460.       /*
  461.            *        get sector #
  462.            */
  463.       if (sscanf (argv[j + 3], "%d", &secno) != 1)
  464.         {
  465.           fprintf (stderr, "Error : Bad sec no\n");
  466.           returnvalue = 3;
  467.         }
  468.       else
  469.         {
  470.           seek ();
  471.         }
  472.       break;
  473.  
  474.     default:
  475.       fprintf (stderr, "Error : bad option\n");
  476.       returnvalue = 3;
  477.     }
  478.     }
  479.   else if (argc == (j + 5))
  480.     /* commands with two parameters */
  481.     {
  482.       ULONG startblock, numblocks;    /* used by the CDDA commands */
  483.       BYTE whichchannel = -1;        /* read left / right channel / stereo */
  484.  
  485.       switch (*++p)
  486.     {
  487.       /*
  488.            ****     read CD-DA (8 bit left|right mono)
  489.            */
  490.     case 'D':
  491.       if ((whichchannel = toupper (*(p + 1))) != 'L'
  492.           && whichchannel != 'R')
  493.         {
  494.           fprintf (stderr, "Error : must be either -DL or -DR\n");
  495.           returnvalue = 3;
  496.         }
  497.       else
  498.         {
  499.           if (sscanf (argv[j + 3], "%lu", &startblock) != 1
  500.               || sscanf (argv[j + 4], "%lu", &numblocks) != 1)
  501.             {
  502.               fprintf(stderr, "Error : invalid parameter for startblock of numblocks\n");
  503.               returnvalue = 3;
  504.             }
  505.           else
  506.             {
  507.                   read_cddaasync (startblock, numblocks, whichchannel,
  508.                   FALSE, 0);
  509.             }
  510.         }
  511.       break;
  512.  
  513. #ifdef USE8SVX
  514.       /*
  515.            ****     read CD-DA (output 8SVX 8 bit left|right|stereo)
  516.            */
  517.     case '8':
  518.       if ((whichchannel = toupper (*(p + 1))) != 'L' && whichchannel != 'R' && whichchannel != 'S')
  519.         {
  520.           fprintf (stderr, "Error : must be -8{L|R|S}\n");
  521.           returnvalue = 3;
  522.         }
  523.       else
  524.         {
  525.           if (sscanf (argv[j + 3], "%lu", &startblock) != 1
  526.               || sscanf (argv[j + 4], "%lu", &numblocks) != 1)
  527.             {
  528.               fprintf(stderr, "Error : invalid parameter for startblock of numblocks\n");
  529.             }
  530.           else
  531.             {
  532.                   write8svx = TRUE;
  533.                   read_cddaasync (startblock, numblocks, whichchannel,
  534.                   FALSE, 0);
  535.             }
  536.         }
  537.       break;
  538. #endif    /* USE8SVX */
  539.  
  540.       /*
  541.            ****     mode sense
  542.            */
  543.     case 'o':
  544.       {
  545.         int control, page;
  546.  
  547.             if (sscanf (argv[j + 3], "%d", &control) != 1 || control < 0 || control > 3)
  548.               {
  549.                 fprintf(stderr, "Error : invalid parameter for control (must be 0-4)\n");
  550.                 returnvalue = 3;
  551.               }
  552.             else
  553.               {
  554.                 if (sscanf (argv[j + 4], "%d", &page) != 1 || page < 0 || page > 0x3f)
  555.                   {
  556.                     fprintf(stderr, "Error : invalid parameter for page (must be 0-0x3f)\n");
  557.                     returnvalue = 3;
  558.                   }
  559.                 else
  560.                   {
  561.                     if (*++p == 'r')
  562.                       /* raw */
  563.                       {
  564.                         mode_sense (FALSE, control, page);
  565.                       }
  566.                     else
  567.                       /* parsed */
  568.                       {
  569.                         mode_sense (TRUE, control, page);
  570.                       }
  571.                   }
  572.               }
  573.       }
  574.           break;
  575.  
  576.  
  577.     default:
  578.       fprintf (stderr, "Error : bad option\n");
  579.       returnvalue = 3;
  580.     }
  581.     }
  582.   else if (argc == (j + 6))
  583.     /* commands with 3 parameters */
  584.     {
  585.       ULONG startblock, numblocks;    /* used by the CDDA commands */
  586.       BYTE whichchannel = -1;        /* read left / right channel / stereo */
  587.       unsigned int subcode = 0;
  588.  
  589.       switch (*++p)
  590.         {
  591.       /*
  592.            ****     read CD-DA (16 bit raw left|right|stereo)
  593.            */
  594.     case 'd':
  595.       if ((whichchannel = toupper (*(p + 1))) != 'L'
  596.           && whichchannel != 'R' && whichchannel != 'S')
  597.         {
  598.           fprintf (stderr, "Error : must be -d{L|R|S}\n");
  599.           returnvalue = 3;
  600.         }
  601.       else
  602.         {
  603.           if (sscanf (argv[j + 3], "%lu", &startblock) != 1
  604.               || sscanf (argv[j + 4], "%lu", &numblocks) != 1)
  605.             {
  606.               fprintf(stderr, "Error : invalid parameter for startblock of numblocks\n");
  607.               returnvalue = 3;
  608.             }
  609.           else
  610.             {
  611.           if (sscanf (argv[j + 5], "%u", &subcode) != 1)
  612.             {
  613.               fprintf(stderr, "Error : invalid parameter for subcode\n");
  614.               returnvalue = 3;
  615.             }
  616.           else
  617.             read_cddaasync (startblock, numblocks, whichchannel,
  618.                     TRUE, subcode);
  619.             }
  620.         }
  621.       break;
  622.  
  623.       /*
  624.            ****     read sub-channel information
  625.            */
  626.     case 'u':    /* raw */
  627.     case 'U':    /* parsed */
  628.       {
  629.         int trackno, subchannelformat, subchannel;
  630.  
  631.             /*
  632.              *        get sub-channel #
  633.              */
  634.             if (sscanf (argv[j + 3], "%d", &subchannel) != 1
  635.                 || subchannel < 0 || subchannel >255)
  636.               {
  637.                 fprintf (stderr, "Error : Sub-channel must be 0-255\n");
  638.                 returnvalue = 3;
  639.               }
  640.             /*
  641.              *        get sub-channel data format #
  642.              */
  643.             if (sscanf (argv[j + 4], "%d", &subchannelformat) != 1
  644.                 || subchannelformat < 0 || subchannelformat >255)
  645.               {
  646.                 fprintf (stderr, "Error : Sub-channel data format must be 0-255\n");
  647.                 returnvalue = 3;
  648.               }
  649.             /*
  650.              *        get track #
  651.              */
  652.             if (sscanf (argv[j + 5], "%d", &trackno) != 1 || trackno < 0
  653.                 || trackno > 99)
  654.               {
  655.                 fprintf (stderr, "Error : Bad track no (must be 1-99)\n");
  656.                 returnvalue = 3;
  657.               }
  658.             else
  659.               {
  660.                 if (*++p == 'r')
  661.                   {
  662.                     read_subchannel (FALSE,subchannel, subchannelformat, trackno);
  663.                   }
  664.                 else
  665.                   {
  666.                     read_subchannel (TRUE,subchannel, subchannelformat, trackno);
  667.                   }
  668.               }
  669.         }
  670.       break;
  671.  
  672.     default:
  673.       fprintf (stderr, "Error : bad option\n");
  674.       returnvalue = 3;
  675.     }
  676.  
  677.     }
  678.  
  679.   else if (argc == (j + 7))
  680.     /* commands with 4 parameters */
  681.     {
  682.       switch (*++p)
  683.     {
  684.       /*
  685.            ****     play audio
  686.            */
  687.     case 'p':
  688.       {
  689.         int starttrack, startindex, endtrack, endindex;
  690.  
  691.             if (sscanf (argv[j + 3], "%d", &starttrack) != 1
  692.                 || (starttrack < 1) || (starttrack > 99))
  693.               {
  694.                 fprintf (stderr, "Error : Starting audio track must be in the range 1-99\n");
  695.                 returnvalue = 3;
  696.                 goto error;
  697.               }
  698.             if (sscanf (argv[j + 4], "%d", &startindex) != 1
  699.                 || (startindex < 0) || (startindex > 99))
  700.               {
  701.                 fprintf (stderr, "Error : Starting audio track index must be in the range 1-99\n");
  702.                 returnvalue = 3;
  703.                 goto error;
  704.               }
  705.             if (sscanf (argv[j + 5], "%d", &endtrack) != 1
  706.                 || (endtrack < 1) || (endtrack > 99))
  707.               {
  708.                 fprintf (stderr, "Error : Ending audio track must be in the range 1-99\n");
  709.                 returnvalue = 3;
  710.                 goto error;
  711.               }
  712.             if (sscanf (argv[j + 6], "%d", &endindex) != 1
  713.                 || (endindex < 0) || (endindex > 99))
  714.               {
  715.                 fprintf (stderr, "Error : Ending audio track index must be in the range 1-99\n");
  716.                 returnvalue = 3;
  717.                 goto error;
  718.               }
  719.             play_audio (starttrack, startindex, endtrack, endindex);
  720.       }
  721.       break;
  722.  
  723.       /*
  724.            ****     change volume settings
  725.            */
  726.     case 'v':
  727.       {
  728.         int i;
  729.         int vol[4];
  730.  
  731.         for (i = 0; i < 4; i++)
  732.           {
  733.         if (sscanf (argv[j + 3 + i], "%d", &vol[i]) != 1
  734.             || (vol[i] < -1) || (vol[i] > 255))
  735.           {
  736.             fprintf (stderr, "Error : Volume %d must be in the range -1 - 255\n", i);
  737.             returnvalue = 3;
  738.             goto error;
  739.           }
  740.           }
  741.         set_volume (vol[0], vol[1], vol[2], vol[3]);
  742.       }
  743.       break;
  744.  
  745.     default:
  746.       fprintf (stderr, "Error : bad option\n");
  747.       returnvalue = 3;
  748.     }
  749.     }
  750.   else
  751.     {
  752.       fprintf (stderr, "Error : bad option\n");
  753.       returnvalue = 3;
  754.     }
  755.  
  756. error:
  757.  
  758.   for (i = 0; i < NDBLBUF; i++)
  759.     {
  760.       if (io_ptr[i])
  761.     {
  762.       CloseDevice ((struct IORequest *) io_ptr[i]);
  763.       DeleteStdIO (io_ptr[i]);
  764.     }
  765.  
  766.       if (cdda_buf[i])
  767.     FreeMem (cdda_buf[i], MAX_CDDALEN);
  768.  
  769.       if (mp_ptr[i])
  770.     DeletePort (mp_ptr[i]);
  771.  
  772.       if (scsi_sense[i])
  773.     FreeMem (scsi_sense[i], SENSE_LEN);
  774.  
  775.       if (mono_buf)
  776.     FreeMem (mono_buf[i], MAX_CDDALEN / 2);
  777.     }
  778.  
  779.   if (toc_buf)
  780.     FreeMem (toc_buf, MAX_TOC_LEN);
  781.  
  782.   if (ip_buf)
  783.     FreeMem (ip_buf, TD_SECTOR);
  784.  
  785.   if (scsi_data)
  786.     FreeMem (scsi_data, MAX_DATA_LEN);
  787.  
  788. #ifdef _DCC
  789.   onbreak(oldbrkhandler);
  790. #endif
  791.   exit (returnvalue);
  792. }
  793.  
  794. /*********************************************************************
  795.  *
  796.  *    Initialization function
  797.  *
  798.  */
  799. BOOLEAN
  800. init (void)
  801. {
  802.   int i;
  803.  
  804.   if ((scsi_data = (UBYTE *) AllocMem (MAX_DATA_LEN, MEMF_CHIP | MEMF_CLEAR)) == NULL)
  805.     {
  806.       fprintf (stderr, "AllocMem(0) Fail\n");
  807.       return FALSE;
  808.     }
  809.  
  810.   if ((ip_buf = (UBYTE *) AllocMem (TD_SECTOR, MEMF_CHIP)) == NULL)
  811.     {
  812.       fprintf (stderr, "AllocMem(2) Fail\n");
  813.       return FALSE;
  814.     }
  815.  
  816.   if ((toc_buf = (UBYTE *) AllocMem (MAX_TOC_LEN, MEMF_CHIP)) == NULL)
  817.     {
  818.       fprintf (stderr, "AllocMem(3) Fail\n");
  819.       return FALSE;
  820.     }
  821.  
  822.   for (i = 0; i < NDBLBUF; i++)
  823.     {
  824.       if ((scsi_sense[i] = (UBYTE *) AllocMem (SENSE_LEN, MEMF_CHIP || MEMF_CLEAR)) == NULL)
  825.     {
  826.       fprintf (stderr, "AllocMem (scsi_sense[%d]) Fail\n",i);
  827.       return FALSE;
  828.     }
  829.       if ((cdda_buf[i] = (UBYTE *) AllocMem (MAX_CDDALEN, 0)) == NULL)
  830.     {
  831.       fprintf (stderr, "AllocMem (cdda_buf[%d]) Fail\n",i);
  832.       return FALSE;
  833.     }
  834.  
  835.       if ((mp_ptr[i] = (MSGPORT *) CreatePort (NULL, 0)) == NULL)
  836.     {
  837.       fprintf (stderr, "CreatePort (mp_ptr[%d]) Fail\n",i);
  838.       return FALSE;
  839.     }
  840.       if ((io_ptr[i] = (IOSTDREQ *) CreateStdIO (mp_ptr[i])) == NULL)
  841.     {
  842.       fprintf (stderr, "CreateStdIO (io_ptr[%d]) Fail\n",i);
  843.       return FALSE;
  844.     }
  845.       if (OpenDevice (dev, scsi_id, (struct IORequest *) io_ptr[i], 0) != 0)
  846.     {
  847.       fprintf (stderr,
  848.            "Error %d while opening SCSI dev \"%s\", unit (%d)\n",
  849.            io_ptr[i]->io_Error, dev, scsi_id, i);
  850.       return FALSE;
  851.     }
  852.       if ((mono_buf[i] = (BYTE *) AllocMem (MAX_CDDALEN / 2, 0)) == NULL)
  853.     {
  854.       fprintf (stderr, "AllocMem (mono_buf[%d]) Fail\n",i);
  855.       return FALSE;
  856.     }
  857.  
  858.     }
  859.  
  860.   return TRUE;
  861. }
  862.  
  863. /*********************************************************************
  864.  *
  865.  *    function to read parameter pages from a device
  866.  */
  867.  
  868. void
  869. mode_sense (BOOLEAN parsed, UBYTE control, UBYTE page)
  870. {
  871.   static SCSICMD6 command =
  872.   {
  873.     SCSI_CMD_MSE,    /* 0x1a MODE SENSE scsi command */
  874.     PAD,        /* LUN | rsrvd. | DBD | rsrvd. */
  875.     0,            /* PC | Page Code */
  876.     PAD,        /* rsrvd. */
  877.     0,            /* allocation length */
  878.     PAD            /* control */
  879.   };
  880.  
  881.   static IDTOSTRING pagecontrolfield[] =
  882.   {
  883.     0x00, "Current Values",
  884.     0x01, "Changeable Values",
  885.     0x02, "Default Values",
  886.     0x03, "Saved Values",
  887.     -1, "Illegal value"
  888.   };
  889.  
  890.   UWORD i,j;
  891.   int err;
  892.  
  893.   command.b2 = (control<<6) | page;
  894.   command.b4 = MAX_DATA_LEN;
  895.  
  896.   if ((err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
  897.                         (UBYTE *) &command, sizeof (command),
  898.                         (SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
  899.     {
  900.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  901.     }
  902.   else
  903.     {
  904.       if (parsed == TRUE)
  905.         /* output parsed data */
  906.         {
  907.           printf ("%s\n", id2string(control, pagecontrolfield));
  908.           printf ("Mode Parameter Header:\n");
  909.           printf (" Mode Data Length: %hu\n", scsi_data[0]);
  910.           printf (" Medium Type: %hu\n", scsi_data[1]);
  911.           printf (" Device-Specific Parameter: %hu\n", scsi_data[2]);
  912.           printf (" Block Descriptor Length: %hu\n", scsi_data[3]);
  913.  
  914.       for (i = 0; i < scsi_data[3]; i +=8)    /* print block descriptors */
  915.         {
  916.           printf("Block Descriptor Density Code: %hu\n",scsi_data[(i)+4]);
  917.           printf(" Number of Blocks: %lu\n", (scsi_data[(i)+5]<<16) + (scsi_data[(i)+6]<<8) + (scsi_data[(i)+7]) );
  918.           printf(" Byte 4 (reserved): %hu\n", scsi_data[(i)+8]);
  919.           printf(" Block length: %lu\n", (scsi_data[(i)+9]<<16) + (scsi_data[(i)+10]<<8) + (scsi_data[(i)+11]) );
  920.         }
  921.  
  922.       for (j = (scsi_data[0]+1), i = scsi_data[3] + 4; i < j; i += scsi_data[i+1] + 2)
  923.         {
  924.           printf("Page Code: %hu\n",scsi_data[i] & 0x3f);
  925.           printf(" Page can%s be saved\n", (scsi_data[i] & 0x80) ? "" : " not");
  926.           printf(" Page Length: %hu\n", scsi_data[i+1]);
  927.           printf(" Mode Parameters:\n");
  928.           rawhexasciioutput(&scsi_data[i+2], scsi_data[i+1], 2);
  929.         }
  930.         }
  931.       else
  932.         /* output raw data */
  933.         {
  934.           rawhexasciioutput(scsi_data, scsi_data[0]+1, 0);
  935.         }
  936.     }
  937. }
  938.  
  939. /*********************************************************************
  940.  *
  941.  *    function to read CD-ROM data block address header
  942.  *    starting block and number of blocks.
  943.  */
  944.  
  945. void
  946. read_cdblockheader (BOOLEAN parsed, ULONG block)
  947. {
  948.   static SCSICMD10 command =
  949.   {
  950.     SCSI_CMD_READHEADER,    /* 0x44 READ HEADER scsi command */
  951.     0,                /* LUN | rsrvd. | MSF | rsrvd. */
  952.     0, 0, 0, 0,            /* Logical Block Address (ULONG) */
  953.     PAD,            /* reserved */
  954.     0,0,            /* allocated data length */
  955.     PAD                /* control */
  956.   };
  957.  
  958.   static IDTOSTRING udatafieldcont[] =
  959.   {
  960.     0x00, "All bytes zero",
  961.     0x01, "User Data",
  962.     0x02, "User Data",
  963.     -1, "Reserved"
  964.   };
  965.  
  966.   static IDTOSTRING auxfieldcont[] =
  967.   {
  968.     0x00, "All bytes zero",
  969.     0x01, "L-EC symbols",
  970.     0x02, "User Data",
  971.     -1, "Reserved"
  972.   };
  973.  
  974.   int err;
  975.  
  976.   command.b2 = block>>24;
  977.   command.b3 = block>>16;
  978.   command.b4 = block>>8;
  979.   command.b5 = block;
  980. #if MAX_CDDALEN > 65536
  981.   command.b7 = 255;
  982.   command.b8 = 255;
  983. #else
  984.   command.b7 = MAX_CDDALEN>>8;
  985.   command.b8 = MAX_CDDALEN & 0xff;
  986. #endif
  987.   if ((err = DoScsiCmd ((UBYTE *) cdda_buf[0], MAX_CDDALEN,
  988.                         (UBYTE *) &command, sizeof (command),
  989.                         (SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
  990.     {
  991.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  992.     }
  993.   else
  994.     {
  995.       if (parsed == TRUE)
  996.         {
  997.           printf("User Data Field Contents (2048 bytes): %d = %s\n",
  998.          (cdda_buf[0])[0], id2string ((cdda_buf[0])[0], udatafieldcont));
  999.           printf("Auxiliary Field Contents ( 288 bytes): %d = %s\n",
  1000.          (cdda_buf[0])[0], id2string ((cdda_buf[0])[0], auxfieldcont));
  1001.           printf("Byte 1 (reserved): %d\n",(cdda_buf[0])[1]);
  1002.           printf("Byte 2 (reserved): %d\n",(cdda_buf[0])[2]);
  1003.           printf("Byte 3 (reserved): %d\n",(cdda_buf[0])[3]);
  1004.           printf("Absolute CD-ROM Address: %lu\n",
  1005.          ((cdda_buf[0])[4] << 24) | ((cdda_buf[0])[5] << 16) | ((cdda_buf[0])[6] << 8) | ((cdda_buf[0])[7]));
  1006.         }
  1007.       else
  1008.         {
  1009.           rawhexasciioutput(cdda_buf[0], 8, 0);
  1010.         }
  1011.     }
  1012. }
  1013.  
  1014. /*********************************************************************
  1015.  *
  1016.  *    function to read subchannel data audio from Sony CDROM with
  1017.  *    starting block and number of blocks.
  1018.  */
  1019.  
  1020. void
  1021. read_subchannel (BOOLEAN parsed, UBYTE subchannel, UBYTE subchannelformat, UBYTE track)
  1022. {
  1023.   static SCSICMD10 command =
  1024.   {
  1025.     SCSI_CMD_READSUBCHANNEL,    /* 0x42 READ SUB-CHANNEL scsi command */
  1026.     0,                /* LUN | rsrvd. | MSF | rsrvd. */
  1027.     0x40,            /* return Sub-Q Channel data */
  1028.     0,                /* Sub-channel Data Format */
  1029.     PAD,
  1030.     PAD,
  1031.     0,                /* Track Number 1-99 */
  1032.     0,0,            /* allocated data length */
  1033.     PAD                /* control */
  1034.   };
  1035.  
  1036.   static IDTOSTRING audiostatus[] =
  1037.   {
  1038.     0x00, "Audio status byte not supported or not valid",
  1039.     0x11, "Audio play operation in progress.",
  1040.     0x12, "Audio play operation paused.",
  1041.     0x13, "Audio play operation successfully completed.",
  1042.     0x14, "Audio play operation stopped due to error.",
  1043.     0x15, "No current audio status to return",
  1044.     -1, "Reserved, unknown or no audio status"
  1045.   };
  1046.  
  1047.   static IDTOSTRING Qfield[] =
  1048.   {
  1049.     0x00, "Sub-channel Q mode information not supplied.",
  1050.     0x01, "Sub-channel Q encodes current position data.",
  1051.     0x02, "Sub-channel Q encodes media catalog number.",
  1052.     0x03, "Sub-channel Q encodes ISRC.",
  1053.     -1, "Reserved"
  1054.   };
  1055.  
  1056.   int err;
  1057.  
  1058.   command.b2 = subchannel;
  1059.   command.b3 = subchannelformat;
  1060.   command.b6 = track;
  1061.  
  1062. #if MAX_CDDALEN > 65536
  1063.   command.b7 = 255;
  1064.   command.b8 = 255;
  1065. #else
  1066.   command.b7 = MAX_CDDALEN & 0xff;
  1067.   command.b8 = MAX_CDDALEN>>8;    /* Allocation length = max. data length */
  1068. #endif
  1069.  
  1070.   if ((err = DoScsiCmd ((UBYTE *) cdda_buf[0], MAX_CDDALEN,
  1071.                         (UBYTE *) &command, sizeof (command),
  1072.                         (SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
  1073.     {
  1074.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  1075.     }
  1076.   else
  1077.     {
  1078.       if (parsed == TRUE)
  1079.         /* parsed output */
  1080.         {
  1081.           if (subchannel == 0x40)
  1082.             {
  1083.               if (subchannelformat == 0)
  1084.                 {
  1085.     /* CHANGE - this doesn't work with my Apple CD300!!!!! */
  1086.           rawhexoutput(cdda_buf[0], ((cdda_buf[0])[2]*256 + (cdda_buf[0])[3])+4);
  1087.                 }
  1088.               else if (subchannelformat == 1)
  1089.                 {
  1090.           printf("Byte 0 (reserved): %02x\n",(cdda_buf[0])[0]);
  1091.           printf("Audio status: %s\n",id2string ((cdda_buf[0])[1],audiostatus));
  1092.           printf("Sub-Channel Data Length: %d\n",((cdda_buf[0])[2]*256 + (cdda_buf[0])[3]));
  1093.           printf("Sub-Channel Data Format code (should be 0x01!): %d\n",(cdda_buf[0])[4]);
  1094.           printf("ADR: %s\n",id2string(((cdda_buf[0])[5]>>4 & 0x0f), Qfield));
  1095.  
  1096.           printf("Audio with%s pre-emphasis.  ", ((cdda_buf[0])[5] & 0x01) ? "" : "out");
  1097.           printf("Digital copy %s\n", ((cdda_buf[0])[5] & 0x02) ? "permitted" : "prohibited");
  1098.           printf("%s track.  ", ((cdda_buf[0])[5] & 0x04) ? "Data" : "Audio");
  1099.           printf("%s channel audio.\n", ((cdda_buf[0])[5] & 0x08) ? "Four" : "Two");
  1100.  
  1101.           printf("Track Number: %d\n", (cdda_buf[0])[6]);
  1102.           printf("Index Number: %d\n", (cdda_buf[0])[7]);
  1103.           printf("Absolute CD-ROM Address: %lu\n", ((cdda_buf[0])[8] << 24) | ((cdda_buf[0])[9] << 16) | ((cdda_buf[0])[10] << 8) | ((cdda_buf[0])[11]));
  1104.           printf("Track Relative CD-ROM Address: %lu\n", ((cdda_buf[0])[12] << 24) | ((cdda_buf[0])[13] << 16) | ((cdda_buf[0])[14] << 8) | ((cdda_buf[0])[15]));
  1105.                 }
  1106.               else if (subchannelformat == 2)
  1107.                 {
  1108.           printf("Byte 0 (reserved): %02x\n",(cdda_buf[0])[0]);
  1109.           printf("Audio status %s\n",id2string ((cdda_buf[0])[1],audiostatus));
  1110.           printf("Sub-Channel Data Length %d\n",((cdda_buf[0])[2]*256 + (cdda_buf[0])[3]));
  1111.           printf("Sub-Channel Data Format code (should be 0x02!): %d\n",(cdda_buf[0])[4]);
  1112.           printf("Byte 5 (reserved): %02x\n",(cdda_buf[0])[5]);
  1113.           printf("Byte 6 (reserved): %02x\n",(cdda_buf[0])[6]);
  1114.           printf("Byte 7 (reserved): %02x\n",(cdda_buf[0])[7]);
  1115.           printf("Byte 8 (reserved): %02x\n",(cdda_buf[0])[8] & 0x7f);
  1116.           printf("MCVal is %s\n", ((cdda_buf[0])[8] & 0x80) ? "true" : "false");
  1117.           printf("Media Catalog Number (UPC/Bar Code):\n");
  1118.           rawhexasciioutput(&(cdda_buf[0])[9], 15, 1);
  1119.                 }
  1120.               else if (subchannelformat == 3)
  1121.                 {
  1122.           printf("Byte 0 (reserved): %02x\n",(cdda_buf[0])[0]);
  1123.           printf("Audio status %s\n",id2string ((cdda_buf[0])[1],audiostatus));
  1124.           printf("Sub-Channel Data Length %d\n",((cdda_buf[0])[2]*256 + (cdda_buf[0])[3]));
  1125.           printf("Sub-Channel Data Format code (should be 0x03!): %d\n",(cdda_buf[0])[4]);
  1126.           printf("ADR: %s\n",id2string(((cdda_buf[0])[5]>>4 & 0x0f) ,Qfield));
  1127.  
  1128.           printf("Audio with%s pre-emphasis.  ", ((cdda_buf[0])[5] & 0x01) ? "" : "out");
  1129.           printf("Digital copy %s\n", ((cdda_buf[0])[5] & 0x02) ? "permitted" : "prohibited");
  1130.           printf("%s track.  ", ((cdda_buf[0])[5] & 0x04) ? "Data" : "Audio");
  1131.           printf("%s channel audio.\n", ((cdda_buf[0])[5] & 0x08) ? "Four" : "Two");
  1132.  
  1133.           printf("Track Number: %d\n", (cdda_buf[0])[6]);
  1134.           printf("Byte 7 (reserved): %02x\n",(cdda_buf[0])[7]);
  1135.           printf("Byte 8 (reserved): %02x\n",(cdda_buf[0])[8] & 0x7f);
  1136.           printf("TCVal is %s\n", ((cdda_buf[0])[8] & 0x80) ? "true" : "false");
  1137.           printf("Track International-Standard-Recording-Code (ISRC):\n");
  1138.           rawhexasciioutput(&(cdda_buf[0])[9], 15, 1);
  1139.                 }
  1140.               else
  1141.                 {
  1142.                   rawhexasciioutput(cdda_buf[0], ((cdda_buf[0])[2]*256 + (cdda_buf[0])[3])+4, 0);
  1143.                 }
  1144.             }
  1145.           else
  1146.             {
  1147.               rawhexasciioutput(cdda_buf[0], ((cdda_buf[0])[2]*256 + (cdda_buf[0])[3])+4, 0);
  1148.             }
  1149.         }
  1150.       else
  1151.         /* raw output */
  1152.         {
  1153.       rawhexasciioutput(cdda_buf[0], ((cdda_buf[0])[2]*256 + (cdda_buf[0])[3])+4, 0);
  1154.         }
  1155.     }
  1156.  
  1157. }
  1158.  
  1159. /*********************************************************************
  1160.  *
  1161.  * subroutine used to printout raw hex data bytes
  1162.  *
  1163.  */
  1164. void
  1165. rawhexoutput (UBYTE *p, UWORD numbytes)
  1166. {
  1167.   UWORD i;
  1168.  
  1169.   for (i = 0; i < numbytes; i++)
  1170.     {
  1171.       printf (" %02x", p[i]);
  1172.     }
  1173.   printf ("\n");
  1174. }
  1175.  
  1176. /*********************************************************************
  1177.  *
  1178.  * subroutine used to printout raw hex data bytes with the
  1179.  * corresponding ASCII values and an index
  1180.  *
  1181.  */
  1182. void
  1183. rawhexasciioutput (UBYTE *p, UWORD numbytes, UBYTE leadspace)
  1184. {
  1185.   UWORD i, j;
  1186.   UBYTE *boff, *aoff;
  1187.   int xxxlen = strlen (" xx");            /* byte */
  1188.  
  1189.   buffer[5+leadspace] = '=';
  1190.  
  1191.   for (i = 0; i < numbytes; i += BYTES_PER_LINE)
  1192.     {
  1193.       memset (buffer, ' ', sizeof (buffer));    /* put spaces in buffer */
  1194.       boff = &buffer[7+leadspace];
  1195.       aoff = boff + (xxxlen * BYTES_PER_LINE) + 1;
  1196.  
  1197.       sprintf (buffer+leadspace, "%04X = ", i);        /* add offset */
  1198.  
  1199.       for (j = 0; (j < BYTES_PER_LINE && (i+j) < numbytes); j++, boff += xxxlen, p++, aoff++)
  1200.         {
  1201.           sprintf (boff, " %02X", *p);
  1202.           *aoff = (isascii (*p) && isprint (*p)) ? *p : '.';
  1203.         }
  1204.  
  1205.       buffer[strlen (buffer)] = ' ';
  1206.       *++aoff = '\n';
  1207.       *++aoff = '\0';
  1208.       printf ("%s", buffer);
  1209.     }
  1210. }
  1211.  
  1212. /*********************************************************************
  1213.  *
  1214.  *    function to read digital audio from Sony / Toshiba CD-ROM with
  1215.  *    starting block and number of blocks.
  1216.  *    This version uses asynchronous reads.
  1217.  *
  1218.  *    outputs LRLRLR pairs of 16 bit digital stereo audio samples,
  1219.  *    2352 / 2368 / 2448 / 96 bytes per CD-ROM block
  1220.  *
  1221.  *      or (depending on 'whichchannel')
  1222.  *
  1223.  *      8 bit digital audio samples, either the left or right channel.
  1224.  */
  1225.  
  1226. #ifdef _DCC
  1227. __stkargs
  1228. #endif
  1229. void
  1230. read_cddaasync (ULONG startblock, ULONG numblocks, BYTE whichchannel,
  1231.         BYTE use16bit, unsigned int subcode)
  1232. {
  1233.   static struct CMD_RDCDDA
  1234.   {
  1235.     UBYTE cmd;            /* READ CD-DA scsi command 0xD8 */
  1236.     UBYTE pad_a;        /* Bits 7-5 Logical Unit Number | Bits 4-1 Reserved | Bit 0 EVPD */
  1237.     ULONG lba;            /* logical block address MSB, , ,LSB */
  1238.     ULONG lbn;            /* number of blocks to transfer MSB, , ,LSB */
  1239.     UBYTE subcode;        /* special sub code selector:
  1240.                       * 0: normal 2352
  1241.                  * 1: 2368
  1242.                  * 2: 2448
  1243.                  * 3: 96 bytes */
  1244.     UBYTE cntrl;        /* Control */
  1245.   } command[NDBLBUF];
  1246.  
  1247.   /*
  1248.    * TOSHIBA XM3401 specific
  1249.    */
  1250.   static SCSICMD6 modecommand;
  1251.   static struct cddamodedata
  1252.   {
  1253.     UWORD pad0;
  1254.     UBYTE pad1;
  1255.     UBYTE bdlength;
  1256.     ULONG density;   /* = densitycode << 24 */
  1257.     ULONG blocklen;
  1258.   } newmodedata;
  1259.  
  1260.  
  1261.   int err, i = 0, j = 0, k = 0, l = 0;
  1262.   ULONG nblocks = numblocks, xblocks;
  1263.  
  1264.   finddrivebrand();        /* determine CD-ROM drive */
  1265.  
  1266.   /*
  1267.    * TOSHIBA XM3401 specific
  1268.    */
  1269.   if (whatdrive == TOSHIBA3401)
  1270.     {
  1271.       /* Read old mode data */
  1272.       modecommand.opcode  = SCSI_CMD_MSE;
  1273.       modecommand.b1      = 0;
  1274.       modecommand.b2      = 1;
  1275.       modecommand.b3      = 0;
  1276.       modecommand.b4      = MAX_DATA_LEN;
  1277.       modecommand.control = 0;
  1278.       if ((err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
  1279.                 (UBYTE *) &modecommand, sizeof (modecommand),
  1280.                 (SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
  1281.     {
  1282.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  1283.       return;
  1284.     }
  1285.       /* Write new mode data */
  1286.       newmodedata.pad0     = 0;
  1287.       newmodedata.pad1     = 0;
  1288.       newmodedata.bdlength = 8;
  1289.       newmodedata.density  = 0x82L << 24;
  1290.       newmodedata.blocklen = 2352;
  1291.       modecommand.opcode = SCSI_CMD_MSL;
  1292.       modecommand.b1     = 0x10;
  1293.       modecommand.b2     = 0;
  1294.       modecommand.b4     = sizeof(struct cddamodedata);
  1295.       if ((err = DoScsiCmd ((UBYTE *) &newmodedata, sizeof(struct cddamodedata),
  1296.                 (UBYTE *) &modecommand, sizeof (modecommand),
  1297.                 (SCSIF_WRITE | SCSIF_AUTOSENSE))) != 0)
  1298.     {
  1299.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  1300.       return;
  1301.     }
  1302.     } /* TOSHIBA */
  1303.  
  1304.   /* reset SCSI status to no command pending
  1305.    */
  1306.   for (i = 0; i < NDBLBUF; i++)
  1307.     scsi_status[i] = 0;
  1308.  
  1309.   for (i = 0; ; (++i >= NDBLBUF)? i = 0 : i)
  1310.     {
  1311.       if (breakcheck ())    /* ^C ? */
  1312.     {
  1313.       /* wait for pending SCSI commands
  1314.        */
  1315.       for (j = 0, i++; j < NDBLBUF; j++, (++i >= NDBLBUF)? i = 0 : i)
  1316.         {
  1317.           if (scsi_status[i] == 1)
  1318.         WaitScsiCmd(i);
  1319.         }
  1320.       return;
  1321.     }
  1322.       if (nblocks > 0)
  1323.     {
  1324.       if (scsi_status[i] == 1)    /* SCSI command pending? */
  1325.         {
  1326.           if ((err = WaitScsiCmd (i)) != 0)    /* read failed, reschedule */
  1327.         {
  1328.           scsi_status[i] = 0;
  1329.           do
  1330.             {
  1331.               fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  1332.  
  1333.               if (breakcheck ())    /* ^C ? */
  1334.             {
  1335.               for (j = 0, i++; j < NDBLBUF; j++, (++i >= NDBLBUF)? i = 0 : i)
  1336.                 {
  1337.                   if (scsi_status[i] == 1)
  1338.                 WaitScsiCmd(i);
  1339.                 }
  1340.               return;
  1341.             }
  1342.               
  1343.               SendScsiCmd (i, (UBYTE *) cdda_buf[i], MAX_CDDALEN,
  1344.                    (UBYTE *) & command[i], sizeof (command[i]),
  1345.                    (SCSIF_READ | SCSIF_AUTOSENSE));
  1346.             }
  1347.           while ((err = WaitScsiCmd (i)) != 0);
  1348.         }
  1349.           scsi_status[i] = 0;    /* no SCSI command pending anymore */
  1350.  
  1351.           if (use16bit == TRUE && whichchannel == 'S')
  1352.         /* output 16 bit stereo samples */
  1353.         {
  1354.           fwrite (cdda_buf[i], scsi_cmd[i].scsi_Actual, 1, stdout);
  1355.         }
  1356.           else if (whichchannel == 'L')
  1357.         /* output left channel */
  1358.         {
  1359.           if (use16bit == FALSE)
  1360.             /* output raw 8 bit left channel */
  1361.             {
  1362.               for (j = 0; j < (scsi_cmd[i].scsi_Actual / 4); j++)
  1363.             {
  1364.               (mono_buf[i])[j] = (BYTE) (((cdda_buf[i])[(4 * j)] +
  1365.                               ((cdda_buf[i])[(4 * j) + 1] * 256)) / 256);
  1366.             }
  1367.               fwrite (mono_buf[i], (scsi_cmd[i].scsi_Actual / 4), 1, stdout);
  1368.             }
  1369.           else
  1370.             /* output raw 16 bit left channel */
  1371.             {
  1372.               for (j = 0, k = 0; j < (scsi_cmd[i].scsi_Actual); j += 4)
  1373.             {
  1374.               (mono_buf[i])[k++] = (BYTE) ((cdda_buf[i])[j]);
  1375.               (mono_buf[i])[k++] = (BYTE) ((cdda_buf[i])[j + 1]);
  1376.             }
  1377.               fwrite (mono_buf[i], (scsi_cmd[i].scsi_Actual / 2), 1, stdout);
  1378.             }
  1379.         }
  1380.           else
  1381.         /* output right channel */
  1382.         {
  1383.           if (use16bit == FALSE)
  1384.             /* output raw 8 bit left channel */
  1385.             {
  1386.               for (j = 0; j < (scsi_cmd[i].scsi_Actual / 4); j++)
  1387.             {
  1388.               (mono_buf[i])[j] = (BYTE) (((cdda_buf[i])[(4 * j) + 2] +
  1389.                               ((cdda_buf[i])[(4 * j) + 3] * 256)) / 256);
  1390.             }
  1391.               fwrite (mono_buf[i], (scsi_cmd[i].scsi_Actual / 4), 1, stdout);
  1392.             }
  1393.           else
  1394.             /* output raw 16 bit left channel */
  1395.             {
  1396.               for (j = 0, k = 0; j < (scsi_cmd[i].scsi_Actual); j += 4)
  1397.             {
  1398.               (mono_buf[i])[k++] = (BYTE) ((cdda_buf[i])[j + 2]);
  1399.               (mono_buf[i])[k++] = (BYTE) ((cdda_buf[i])[j + 3]);
  1400.             }
  1401.               fwrite (mono_buf[i], (scsi_cmd[i].scsi_Actual / 2), 1, stdout);
  1402.             }
  1403.         }
  1404.         }    /* (scsi_status[i] == 1) ? */
  1405.  
  1406.       if (whatdrive == TOSHIBA3401)
  1407.             {
  1408.               command[i].cmd = SCSI_CMD_READ12;   /* TOSHIBA XM3401 */
  1409.             }
  1410.       else
  1411.         {
  1412.               command[i].cmd = SCSI_CMD_READCDDA; /* Sony CDU-5*1 */
  1413.             }
  1414.           command[i].pad_a = 0;
  1415.           command[i].lba = startblock;
  1416.           command[i].lbn = xblocks = (nblocks > NUM_OF_CDDAFRAMES)? NUM_OF_CDDAFRAMES : nblocks;
  1417.       command[i].subcode = subcode;
  1418.       command[i].cntrl = 0;
  1419.  
  1420.       startblock += xblocks;
  1421.       nblocks -= xblocks;
  1422.  
  1423.       scsi_status[i] = 1;    /* Status: SCSI command pending */
  1424.  
  1425.       SendScsiCmd (i, (UBYTE *) cdda_buf[i], MAX_CDDALEN,
  1426.                (UBYTE *) & command[i], sizeof (command[i]),
  1427.                (SCSIF_READ | SCSIF_AUTOSENSE));
  1428.  
  1429.     }
  1430.       else    /* nblocks <= 0 */
  1431.     {
  1432.       /* wait for all pending requests */
  1433.       for (l = 0; l < NDBLBUF; l++)
  1434.         {
  1435.           if (scsi_status[i] == 1)    /* SCSI command pending ? */
  1436.         {
  1437.           if ((err = WaitScsiCmd (i)) != 0) /* SCSI command failed? */
  1438.             {
  1439.               scsi_status[i] = 0;
  1440.               do    /* reschedule SCSI command */
  1441.             {
  1442.               fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  1443.  
  1444.               if (breakcheck ()) /* ^C ? */
  1445.                 {
  1446.                   /* wait for pending SCSI commands
  1447.                    */
  1448.                   for (j = 0, i++; j < NDBLBUF; j++, (++i >= NDBLBUF)? i = 0 : i)
  1449.                 {
  1450.                   if (scsi_status[i] == 1)
  1451.                     WaitScsiCmd(i);
  1452.                 }
  1453.                   return;
  1454.                 }
  1455.               
  1456.               SendScsiCmd (i, (UBYTE *) cdda_buf[i], scsi_cmd[i].scsi_Length,
  1457.                        (UBYTE *) & command[i], sizeof (command[i]),
  1458.                        (SCSIF_READ | SCSIF_AUTOSENSE));
  1459.               
  1460.             }
  1461.               while ((err = WaitScsiCmd (i)) != 0);
  1462.             }
  1463.           scsi_status[i] = 0;    /* Status: no SCSI command pending */
  1464.  
  1465.           if (use16bit == TRUE && whichchannel == 'S')
  1466.             /* output 16 bit stereo samples */
  1467.             {
  1468.               fwrite (cdda_buf[i], scsi_cmd[i].scsi_Actual, 1, stdout);
  1469.             }
  1470.           else if (whichchannel == 'L')
  1471.             /* output left channel */
  1472.             {
  1473.               if (use16bit == FALSE)
  1474.             /* output raw 8 bit left channel */
  1475.             {
  1476.               for (j = 0; j < (scsi_cmd[i].scsi_Actual / 4); j++)
  1477.                 {
  1478.                   (mono_buf[i])[j] = (BYTE) (((cdda_buf[i])[(4 * j)] +
  1479.                               ((cdda_buf[i])[(4 * j) + 1] * 256)) / 256);
  1480.                 }
  1481.               fwrite (mono_buf[i], (scsi_cmd[i].scsi_Actual / 4), 1, stdout);
  1482.             }
  1483.               else
  1484.             /* output raw 16 bit left channel */
  1485.             {
  1486.               for (j = 0, k = 0; j < (scsi_cmd[i].scsi_Actual); j += 4)
  1487.                 {
  1488.                   (mono_buf[i])[k++] = (BYTE) ((cdda_buf[i])[j]);
  1489.                   (mono_buf[i])[k++] = (BYTE) ((cdda_buf[i])[j + 1]);
  1490.                 }
  1491.               fwrite (mono_buf[i], (scsi_cmd[i].scsi_Actual / 2), 1, stdout);
  1492.             }
  1493.             }
  1494.           else
  1495.             /* output right channel */
  1496.             {
  1497.               if (use16bit == FALSE)
  1498.             /* output raw 8 bit left channel */
  1499.             {
  1500.               for (j = 0; j < (scsi_cmd[i].scsi_Actual / 4); j++)
  1501.                 {
  1502.                   (mono_buf[i])[j] = (BYTE) (((cdda_buf[i])[(4 * j) + 2] +
  1503.                               ((cdda_buf[i])[(4 * j) + 3] * 256)) / 256);
  1504.                 }
  1505.               fwrite (mono_buf[i], (scsi_cmd[i].scsi_Actual / 4), 1, stdout);
  1506.             }
  1507.               else
  1508.             /* output raw 16 bit left channel */
  1509.             {
  1510.               for (j = 0, k = 0; j < (scsi_cmd[i].scsi_Actual); j += 4)
  1511.                 {
  1512.                   (mono_buf[i])[k++] = (BYTE) ((cdda_buf[i])[j + 2]);
  1513.                   (mono_buf[i])[k++] = (BYTE) ((cdda_buf[i])[j + 3]);
  1514.                 }
  1515.               fwrite (mono_buf[i], (scsi_cmd[i].scsi_Actual / 2), 1, stdout);
  1516.             }
  1517.             }        /* output right channel */
  1518.  
  1519.           scsi_status[i] = 0;
  1520.  
  1521.         }    /* (scsi_status[i] == 1) ? */
  1522.  
  1523.           (++i >= NDBLBUF)? i = 0 : i;
  1524.  
  1525.         }  /* for (l = 0; l < NDBLBUF; l++) */
  1526.  
  1527.       break;
  1528.     }
  1529.     }
  1530.   if (whatdrive == TOSHIBA3401)
  1531.     {
  1532.       /*
  1533.        * TOSHIBA XM3401 specific
  1534.        */
  1535.       /* Write old mode data */
  1536.       newmodedata.density  = ((struct cddamodedata *) scsi_data)->density;
  1537.       newmodedata.blocklen = ((struct cddamodedata *) scsi_data)->blocklen;
  1538.       if ((err = DoScsiCmd ((UBYTE *) &newmodedata, sizeof(struct cddamodedata),
  1539.                 (UBYTE *) &modecommand, sizeof (modecommand),
  1540.                 (SCSIF_WRITE | SCSIF_AUTOSENSE))) != 0)
  1541.     {
  1542.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  1543.     }
  1544.     }
  1545. }
  1546.  
  1547. /*********************************************************************
  1548.  *
  1549.  *    function to read sectors from a starting sector #
  1550.  *    - similar adjacent lines are suppressed on printout.
  1551.  *
  1552.  *    - uses trackdisk.device
  1553.  */
  1554.  
  1555. void
  1556. read_sec (void)
  1557.  
  1558. {
  1559.   UBYTE *sec_click_ptr;        /* click = 16 bytes    */
  1560.   UBYTE *pref;
  1561.   UBYTE *p;
  1562.   UWORD j;
  1563.   UWORD k;
  1564.   int err;
  1565.  
  1566.   /*
  1567.    *  keep printing sectors until ^C , or until error
  1568.    */
  1569.   io_ptr[0]->io_Command = CMD_READ;
  1570.   io_ptr[0]->io_Length = TD_SECTOR;
  1571.   io_ptr[0]->io_Data = (APTR) ip_buf;
  1572.   io_ptr[0]->io_Offset = secno * TD_SECTOR;    /* will be updated... */
  1573.  
  1574.  
  1575.   /*
  1576.    *  keep reading sectors : stop on ^C on bad sector #
  1577.    */
  1578.   for (;; ++secno)
  1579.     {
  1580.       UBYTE *ss;
  1581.       UWORD m_sec_offs;
  1582.  
  1583.       if (breakcheck ())    /* ^C ? */
  1584.     break;
  1585.  
  1586.       io_ptr[0]->io_Offset = secno * TD_SECTOR;    /* sector offset */
  1587.  
  1588.       DoIO ((struct IORequest *) io_ptr[0]);
  1589.       if ((err = io_ptr[0]->io_Error) == 0)
  1590.     {
  1591.       printf ("\n");
  1592.       /*
  1593.        * scan this sector ...
  1594.         */
  1595.       for (sec_click_ptr = pref = ip_buf, m_sec_offs = 0;
  1596.            m_sec_offs < TD_SECTOR;
  1597.            m_sec_offs += BYTES_PER_LINE, sec_click_ptr += BYTES_PER_LINE)
  1598.         {
  1599.           int xxxlen = strlen (" xx");    /* byte */
  1600.  
  1601.           /*
  1602.            * don't print line if same contents as previous
  1603.            */
  1604.           if (gcomp (sec_click_ptr, pref, BYTES_PER_LINE) == TRUE)
  1605.         {
  1606.           if (m_sec_offs > 1)
  1607.             continue;    /* same */
  1608.         }
  1609.           memset (buffer, ' ', sizeof (buffer));    /* put spaces in buffer */
  1610.  
  1611.           sprintf (buffer, "%05X:%03X = ", secno, m_sec_offs);
  1612.  
  1613.           /* set up for loop */
  1614.  
  1615.           k = strlen (buffer);
  1616.           ss = buffer + k;
  1617.           k += (BYTES_PER_LINE * xxxlen) + 1;
  1618.           for (p = sec_click_ptr, j = 0;
  1619.            j < BYTES_PER_LINE;
  1620.            ss += xxxlen, ++j, ++k)
  1621.         {
  1622.           UBYTE dd = *p++;
  1623.           UBYTE que = (isascii (dd) && isprint (dd)) ? dd : '.';
  1624.           sprintf (ss, " %02X", dd);    /* 2 hex charas  */
  1625.           buffer[k] = que;
  1626.         }
  1627.  
  1628.           buffer[strlen (buffer)] = ' ';
  1629.           buffer[k++] = '\n';
  1630.           buffer[k++] = '\0';
  1631.  
  1632.           printf ("%s", buffer);
  1633.           pref = sec_click_ptr;
  1634.  
  1635.         }
  1636.     }
  1637.       else
  1638.     {
  1639.       /* else DoIO error */
  1640.  
  1641.       fprintf (stderr, "Error :  err = %ld , sec = %ld dec , $%lX , [%s]\n",
  1642.            err, secno, secno, sense_errs (0, err));
  1643.  
  1644.       return;
  1645.     }
  1646.     }
  1647. }
  1648.  
  1649. /*********************************************************************
  1650.  *
  1651.  *    function to read sectors from a starting sector #
  1652.  *    - similar adjacent lines are suppressed on printout.
  1653.  *
  1654.  *    - uses scsi device directly
  1655.  */
  1656.  
  1657. void
  1658. read_sec_scsi (void)
  1659. {
  1660.   static struct CMD_XREAD
  1661.   {
  1662.     UBYTE cmd;
  1663.     UBYTE lba[3];
  1664.     UBYTE numb_secs;
  1665.     UBYTE pad;
  1666.   } command =
  1667.   {
  1668.     SCSI_CMD_RD,
  1669.     0, 0, 0,
  1670.     0,
  1671.     PAD
  1672.   };
  1673.  
  1674.   UBYTE *sec_click_ptr;        /* click = 16 bytes    */
  1675.   UBYTE *pref;
  1676.   UBYTE *p;
  1677.   UWORD j;
  1678.   UWORD k;
  1679.   int err;
  1680.  
  1681.   /*
  1682.    *  keep printing sectors until ^C , or until error
  1683.    */
  1684.  
  1685.  
  1686.   /*
  1687.    *  keep reading sectors : stop on ^C on bad sector #
  1688.    */
  1689.   for (;; ++secno)
  1690.     {
  1691.       UBYTE *ss;
  1692.       UWORD m_sec_offs;
  1693.  
  1694.       command.lba[2] = secno;
  1695.       command.lba[1] = secno >> 8;
  1696.       command.lba[0] = (secno >> 8) & 0x1F;
  1697.  
  1698.       command.numb_secs = 1;
  1699.  
  1700.       if (breakcheck ())    /* ^C ? */
  1701.     break;
  1702.  
  1703.       io_ptr[0]->io_Offset = secno * TD_SECTOR;    /* sector offset */
  1704.  
  1705.       if ((err = DoScsiCmd ((UBYTE *) ip_buf, 512,
  1706.                 (UBYTE *) & command, sizeof (command),
  1707.                 (SCSIF_READ | SCSIF_AUTOSENSE))) == 0)
  1708.     {
  1709.       printf ("\n");
  1710.       /*
  1711.        * scan this sector ...
  1712.         */
  1713.       for (sec_click_ptr = pref = ip_buf, m_sec_offs = 0;
  1714.            m_sec_offs < TD_SECTOR;
  1715.            m_sec_offs += BYTES_PER_LINE, sec_click_ptr += BYTES_PER_LINE)
  1716.         {
  1717.           int xxxlen = strlen (" xx");    /* byte */
  1718.  
  1719.           /*
  1720.            * don't print line if same contents as previous
  1721.            */
  1722.           if (gcomp (sec_click_ptr, pref, BYTES_PER_LINE) == TRUE)
  1723.         {
  1724.           if (m_sec_offs > 1)
  1725.             continue;    /* same */
  1726.         }
  1727.           memset (buffer, ' ', sizeof (buffer));    /* put spaces in buffer */
  1728.  
  1729.           sprintf (buffer, "%05X:%03X = ", secno, m_sec_offs);
  1730.  
  1731.           /* set up for loop */
  1732.  
  1733.           k = strlen (buffer);
  1734.           ss = buffer + k;
  1735.           k += (BYTES_PER_LINE * xxxlen) + 1;
  1736.           for (p = sec_click_ptr, j = 0;
  1737.            j < BYTES_PER_LINE;
  1738.            ss += xxxlen, ++j, ++k)
  1739.         {
  1740.           UBYTE dd = *p++;
  1741.           UBYTE que = (isascii (dd) && isprint (dd)) ? dd : '.';
  1742.           sprintf (ss, " %02X", dd);    /* 2 hex charas  */
  1743.           buffer[k] = que;
  1744.         }
  1745.  
  1746.           buffer[strlen (buffer)] = ' ';
  1747.           buffer[k++] = '\n';
  1748.           buffer[k++] = '\0';
  1749.  
  1750.           printf ("%s", buffer);
  1751.           pref = sec_click_ptr;
  1752.  
  1753.         }
  1754.     }
  1755.       else
  1756.     {
  1757.       /* else DoIO error */
  1758.  
  1759.       fprintf (stderr, "Error :  sec = %ld dec , $%lX , [%s]\n",
  1760.            secno, secno, sense_errs (0, err));
  1761.       return;
  1762.     }
  1763.     }
  1764. }
  1765.  
  1766. /*********************************************************************
  1767.  *
  1768.  *    function to prevent/allow allow medium removal
  1769.  *
  1770.  */
  1771.  
  1772. void
  1773.  
  1774. medium_removal(int lock)
  1775. {
  1776.   static SCSICMD6 command =
  1777.   {
  1778.     SCSI_CMD_PAMR,        /* 0x1E SCSI Prevent Allow Medium Removal */
  1779.     0,                /* Bit 765 = LUN */
  1780.     PAD,            /* reserved */
  1781.     PAD,            /* reserved */
  1782.     0,                /* Bit 0 = prevent */
  1783.     PAD,            /* reserved */
  1784.   };
  1785.  
  1786.   int err;
  1787.  
  1788.   command.b4 = lock;
  1789.  
  1790.   if ((err = DoScsiCmd (0, 0,
  1791.             (UBYTE *) & command, sizeof (command),
  1792.             (SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
  1793.     {
  1794.       fprintf (stderr, "Error :   err=%ld , [%s]\n", err, sense_errs (0, err));
  1795.     }
  1796. }
  1797.  
  1798. /*********************************************************************
  1799.  *
  1800.  *    function to stop/start motor on SCSI device
  1801.  *    or eject/insert a medium
  1802.  *
  1803.  */
  1804.  
  1805. void
  1806. motor (int motorstatus)
  1807. {
  1808.   static SCSICMD6 command =
  1809.   {
  1810.     SCSI_CMD_SSU,        /* 0x1B SCSI Start / Stop Unit */
  1811.     0,
  1812.     PAD,
  1813.     PAD,
  1814.     0,                /* start/stop eject/insert */
  1815.     PAD,
  1816.   };
  1817.  
  1818.   int err;
  1819.  
  1820.   command.b4 = motorstatus;
  1821.  
  1822.   if ((err = DoScsiCmd (0, 0,
  1823.             (UBYTE *) & command, sizeof (command),
  1824.             (SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
  1825.     {
  1826.       fprintf (stderr, "Error :   err=%ld , [%s]\n", err, sense_errs (0, err));
  1827.     }
  1828. }
  1829.  
  1830. /*********************************************************************
  1831.  *
  1832.  *    function to seek to a cylinder
  1833.  *
  1834.  */
  1835.  
  1836. void
  1837. seek (void)
  1838.  
  1839. {
  1840.   static struct CMD_SEEK
  1841.   {
  1842.     UBYTE cmd;
  1843.     UBYTE pad_a;
  1844.     ULONG lba;
  1845.     UBYTE pad[4];
  1846.   } command =
  1847.   {
  1848.     SCSI_CMD_SKX,
  1849.     PAD,
  1850.     0,
  1851.     PAD, PAD, PAD, PAD
  1852.   };
  1853.  
  1854.   int err;
  1855.   /*
  1856.    *    load sector # (log block addr)
  1857.    */
  1858.  
  1859.   command.lba = secno;
  1860.  
  1861.   if ((err = DoScsiCmd (0, 0,
  1862.             (UBYTE *) & command, sizeof (command),
  1863.             (SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
  1864.     {
  1865.       fprintf (stderr, "Error :  err = %ld , sec = %ld dec , $%lX , [%s]\n",
  1866.            err, secno, secno, sense_errs (0, err));
  1867.     }
  1868. }
  1869.  
  1870.  
  1871. /*********************************************************************
  1872.  *
  1873.  *    what CD-ROM drive?
  1874.  *
  1875.  */
  1876.  
  1877. void
  1878. finddrivebrand (void)
  1879. {
  1880.   static SCSICMD6 command =
  1881.   {
  1882.     SCSI_CMD_INQ,        /* 0x12 INQUIRY */
  1883.     PAD,            /* Bits 7-5 Logical Unit Number | Bits 4-1 Reserved | Bit 0 EVPD */
  1884.     PAD,            /* Page Code */
  1885.     PAD,            /* Reserved */
  1886.     0,                /* Allocation length */
  1887.     PAD                /* Control */
  1888.   };
  1889.  
  1890.   int err;
  1891.  
  1892.   command.b4 = MAX_DATA_LEN;    /* Allocation length = max. data length */
  1893.  
  1894.   if ((err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
  1895.             (UBYTE *) & command, sizeof (command),
  1896.             (SCSIF_READ | SCSIF_AUTOSENSE))) == 0)
  1897.     {
  1898.       int rem = scsi_cmd[0].scsi_Actual;
  1899.  
  1900.       if (rem >= 8)
  1901.     {
  1902.       if (!memcmp("SONY    CD-ROM CDU-8003",
  1903.                &scsi_data[8], strlen("SONY    CD-ROM CDU-8003")))
  1904.         {
  1905.           whatdrive = APPLECD300;
  1906.         }
  1907.       else if (!memcmp("SONY    CD-ROM CDU-8002",
  1908.                 &scsi_data[8], strlen("SONY    CD-ROM CDU-8002")))
  1909.         {
  1910.           whatdrive = APPLECD150;
  1911.         }
  1912.       else if (!memcmp("TOSHIBA",
  1913.                 &scsi_data[8], strlen("TOSHIBA")))
  1914.         {
  1915.           whatdrive = TOSHIBA3401;
  1916.         }
  1917.     }
  1918.       else
  1919.     whatdrive = UNKNOWN;
  1920.     }
  1921.   else
  1922.     /* error */
  1923.     {
  1924.       fprintf (stderr, "Error : err=%ld , %s\n", err, sense_errs (0, err));
  1925.     }
  1926. }
  1927.  
  1928. /*********************************************************************
  1929.  *
  1930.  *    function to set the output volume of a CD-ROM drive
  1931.  *
  1932.  *    if (vol0 = vol1 = vol2 = vol3) == -1
  1933.  *     display current volume settings, don't change anything
  1934.  *
  1935.  */
  1936.  
  1937. void
  1938. set_volume (int vol0, int vol1, int vol2, int vol3)
  1939. {
  1940.   static int err, i, j;
  1941.   static SCSICMD6 modecommand;
  1942.   static struct volmodedata
  1943.     {
  1944.       UBYTE head[4];
  1945.       UBYTE page;    /* page code 0x0E */
  1946.       UBYTE plength;    /* page length */
  1947.       UBYTE b2;        /* bit 2: Immed, bit 1: SOTC */
  1948.       UBYTE b3;        /* reserved */
  1949.       UBYTE b4;        /* reserved */
  1950.       UBYTE b5;        /* bit 7: APRVal, bit 3-0: format of LBAs / Sec. */
  1951.       UWORD bps;    /* logical blocks per second audio playback */
  1952.       UBYTE out0;    /* lower 4 bits: output port 0 channel selection */
  1953.       UBYTE vol0;    /* output port 0 volume */
  1954.       UBYTE out1;    /* lower 4 bits: output port 1 channel selection */
  1955.       UBYTE vol1;    /* output port 1 volume */
  1956.       UBYTE out2;    /* lower 4 bits: output port 2 channel selection */
  1957.       UBYTE vol2;    /* output port 2 volume */
  1958.       UBYTE out3;    /* lower 4 bits: output port 3 channel selection */
  1959.       UBYTE vol3;    /* output port 3 volume */
  1960.     } modedata;
  1961.  
  1962.   for (i = 0; i < 4; i++)
  1963.     modedata.head[i] = 0;
  1964.  
  1965.   modecommand.opcode    = SCSI_CMD_MSE;
  1966.   modecommand.b1    = 0;
  1967.   modecommand.b2    = 0x0E;
  1968.   modecommand.b3    = 0;
  1969.   modecommand.b4    = MAX_DATA_LEN;
  1970.   modecommand.control    = 0;
  1971.  
  1972.   if ((err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
  1973.             (UBYTE *) &modecommand, sizeof (modecommand),
  1974.             (SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
  1975.     {
  1976.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  1977.       return;
  1978.     }
  1979.  
  1980.   for (j = (scsi_data[0]+1), i = scsi_data[3] + 4; i < j; i += scsi_data[i+1] + 2)
  1981.     {
  1982.       if (vol0 == -1 && vol1 == -1 && vol2 == -1 && vol3 == -1)
  1983.     {
  1984.       if ((scsi_data[i] & 0x3f) == 0x0e)
  1985.         {
  1986.           printf ("Immed    : %s\n", (scsi_data[i+2] & 4)? "yes" : "no");
  1987.           printf ("SOTC     : %s\n", (scsi_data[i+2] & 2)? "yes" : "no");
  1988.           printf ("APRVal   : %svalid\n", (scsi_data[i+5] & 0x80)? "" : "in");
  1989.           if (scsi_data[i+5] & 0x80)
  1990.         {
  1991.           printf ("LBA Format: ");
  1992.           if ((scsi_data[i+5] & 0x0f) == 0)
  1993.             printf ("1 second\n");
  1994.           else if ((scsi_data[i+5] & 0x0f) == 8)
  1995.             printf ("1/256 second\n");
  1996.           else
  1997.             printf ("%hu (reserved)\n", scsi_data[i+5] & 0x0f);
  1998.           printf ("LBPS      : %u\n", scsi_data[i+6]<<8 + scsi_data[i+7]);
  1999.         }
  2000.         }
  2001.       if (scsi_data[i+8] & 0x0f)
  2002.         printf ("Output 0 : %hu\n", scsi_data[i+8] & 0x0f);
  2003.       else
  2004.         printf ("Output 0 : muted\n");
  2005.       printf ("Volume 0 : %hu\n", scsi_data[i+9]);
  2006.       if (scsi_data[i+10] & 0x0f)
  2007.         printf ("Output 1 : %hu\n", scsi_data[i+10] & 0x0f);
  2008.       else
  2009.         printf ("Output 1 : muted\n");
  2010.       printf ("Volume 1 : %hu\n", scsi_data[i+11]);
  2011.       if (scsi_data[i+12] & 0x0f)
  2012.         printf ("Output 2 : %hu\n", scsi_data[i+12] & 0x0f);
  2013.       else
  2014.         printf ("Output 2 : muted\n");
  2015.       printf ("Volume 2 : %hu\n", scsi_data[i+13]);
  2016.       if (scsi_data[i+14] & 0x0f)
  2017.         printf ("Output 3 : %hu\n", scsi_data[i+14] & 0x0f);
  2018.       else
  2019.         printf ("Output 3 : muted\n");
  2020.       printf ("Volume 3 : %hu\n", scsi_data[i+15]);
  2021.     }
  2022.       
  2023.       /* should be 16 bytes */
  2024.       memcpy (&modedata.page, &scsi_data[i], 16);
  2025.     }
  2026.   if (vol0 > -1 || vol1 > -1 || vol2 > -1 || vol3 > -1)
  2027.     {
  2028.       modedata.page = 0x0e;
  2029.       modedata.plength = 0x0e;
  2030.  
  2031.       if (vol0 >= 0)
  2032.     modedata.vol0 = vol0;
  2033.       if (vol1 >= 0)
  2034.     modedata.vol1 = vol1;
  2035.       if (vol2 >= 0)
  2036.     modedata.vol2 = vol2;
  2037.       if (vol3 >= 0)
  2038.     modedata.vol3 = vol3;
  2039.  
  2040.       modecommand.opcode    = SCSI_CMD_MSL;
  2041.       modecommand.b1        = 0x10;
  2042.       modecommand.b2        = 0;
  2043.       modecommand.b3        = 0;
  2044.       modecommand.b4        = sizeof (modedata);
  2045.       modecommand.control    = 0;
  2046.  
  2047.       if ((err = DoScsiCmd ((UBYTE *) &modedata, sizeof(modedata),
  2048.                 (UBYTE *) &modecommand, sizeof (modecommand),
  2049.                 (SCSIF_WRITE | SCSIF_AUTOSENSE))) != 0)
  2050.     {
  2051.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  2052.       return;
  2053.     }
  2054.     }
  2055. }
  2056.  
  2057. /*********************************************************************
  2058.  *
  2059.  *    function to make an inquiry
  2060.  *
  2061.  */
  2062.  
  2063. void
  2064. inquiry (BOOLEAN parsedoutput)
  2065. {
  2066.   static SCSICMD6 command =
  2067.   {
  2068.     SCSI_CMD_INQ,        /* 0x12 INQUIRY */
  2069.     PAD,            /* Bits 7-5 Logical Unit Number | Bits 4-1 Reserved | Bit 0 EVPD */
  2070.     PAD,            /* Page Code */
  2071.     PAD,            /* Reserved */
  2072.     0,                /* Allocation length */
  2073.     PAD                /* Control */
  2074.   };
  2075.   static int err;
  2076.  
  2077.   command.b4 = MAX_DATA_LEN;    /* Allocation length = max. data length */
  2078.  
  2079.   if ((err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
  2080.             (UBYTE *) & command, sizeof (command),
  2081.             (SCSIF_READ | SCSIF_AUTOSENSE))) == 0)
  2082.     {
  2083.       int rem = scsi_cmd[0].scsi_Actual;
  2084.  
  2085.       if (parsedoutput == FALSE)
  2086.     {
  2087.       rawhexasciioutput (scsi_data, rem, 0);
  2088.     }
  2089.       else
  2090.     /* parsed output */
  2091.     {
  2092.       static IDTOSTRING devicetype[] =
  2093.       {
  2094.         0x00, "Direct-access device (e.g., magnetic disk)",
  2095.         0x01, "Sequential-access device (e.g., magnetic tape)",
  2096.         0x02, "Printer device",
  2097.         0x03, "Processor device",
  2098.         0x04, "Write-once device (e.g., some optical disks)",
  2099.         0x05, "CD-ROM device",
  2100.         0x06, "Scanner device",
  2101.         0x07, "Optical memory device (e.g., some optical disks)",
  2102.         0x08, "Medium Changer device (e.g., jukeboxes)",
  2103.         0x09, "Communications device",
  2104.         0x0A, "Defined by ASC IT8 (Graphic Arts Pre-Press Devices)",
  2105.         0x0B, "Defined by ASC IT8 (Graphic Arts Pre-Press Devices)",
  2106.         -1, "Reserved, unknown or no device type"
  2107.       };
  2108.  
  2109.       static IDTOSTRING ansiversion[] =
  2110.       {
  2111.         0x00, "The device might or might not comply to an ANSI-approved standard.",
  2112.         0x01, "The device complies to ANSI X3.131-1986 (SCSI-1).",
  2113.         0x02, "The device complies to (SCSI-2).",
  2114.         -1, "Reserved",
  2115.       };
  2116.  
  2117.       static IDTOSTRING responseformat[] =
  2118.       {
  2119.         0x00, "SCSI-1",
  2120.         0x01, "CCS",
  2121.         0x02, "SCSI-2",
  2122.         -1, "Reserved",
  2123.       };
  2124.  
  2125.       printf ("Peripherial qualifier: %ld\n", (scsi_data[0] & 0xE0) >> 5);
  2126.       printf ("Peripherial device type: $%lx, %s\n", (scsi_data[0] & 0x1F), id2string ((scsi_data[0] & 0x1F), devicetype));
  2127.  
  2128.       printf ("Removable medium: %s\n", (scsi_data[1] & 0x80) ? "yes" : "no");
  2129.       printf ("Device type modifier: %lx\n", scsi_data[1] & 0x7F);
  2130.       printf ("ISO Version: %lx\n", (scsi_data[2] & 0xC0) >> 6);
  2131.       printf ("ECMA Version: %lx\n", (scsi_data[2] & 0x38) >> 3);
  2132.  
  2133.       printf ("ANSI-Approved Version: %ld, %s\n", scsi_data[2] & 0x07, id2string ((scsi_data[2] & 0x07), ansiversion));
  2134.  
  2135.       printf ("AENC: %s\n", (scsi_data[3] & 0x80) ? "yes" : "no");
  2136.       printf ("TrmIOP: does%s support TERMINATE I/O PROCESs message\n", (scsi_data[3] & 0x40) ? "" : "n't");
  2137.  
  2138.       printf ("Response data format: $%lx, conforms to %s\n", scsi_data[3] & 0x0F, id2string ((scsi_data[3] & 0x0F), responseformat));
  2139.       printf ("Additional length: $%lx\n", scsi_data[4]);
  2140.       printf ("INQUIRY[5-6] (Reserved): $%lx, $%lx\n", scsi_data[5], scsi_data[6]);
  2141.       printf ("RelAdr: does%s support relative addressing\n", (scsi_data[7] & 0x80) ? "" : "n't");
  2142.       printf ("WBus32: does%s support 32 wide data transfers\n", (scsi_data[7] & 0x40) ? "" : "n't");
  2143.       printf ("WBus16: does%s support 16 wide data transfers\n", (scsi_data[7] & 0x20) ? "" : "n't");
  2144.       printf ("Sync: does%s support synchronous transfers\n", (scsi_data[7] & 0x10) ? "" : "n't");
  2145.       printf ("Linked: does%s support linked commands\n", (scsi_data[7] & 0x08) ? "" : "n't");
  2146.       printf ("CmdQue: does%s support tagged command queueing\n", (scsi_data[7] & 0x02) ? "" : "n't");
  2147.       printf ("SftRe: responds to RESET condition with %s RESET alternative\n", (scsi_data[7] & 0x01) ? "soft" : "hard");
  2148.       printf ("Vendor identification: %.8s\n", &scsi_data[8]);
  2149.       printf ("Product identification: %.16s\n", &scsi_data[16]);
  2150.       printf ("Product revision level: %.4s\n", &scsi_data[32]);
  2151.       printf ("Vendor specific: %.20s\n", &scsi_data[36]);
  2152.       printf ("Reserved: %.35s\n", &scsi_data[56]);
  2153.     }
  2154.     }
  2155.   else
  2156.     /* error */
  2157.     {
  2158.       fprintf (stderr, "Error : err=%ld , %s\n", err, sense_errs (0, err));
  2159.     }
  2160. }
  2161.  
  2162. /*********************************************************************
  2163.  *
  2164.  *    function to read disk capacity
  2165.  *
  2166.  */
  2167.  
  2168. void
  2169. read_capacity (BOOLEAN parsed)
  2170. {
  2171.   static struct CMD_READ_CAPACITY
  2172.   {
  2173.     UBYTE cmd;
  2174.     UBYTE pad_a;
  2175.     ULONG lba;
  2176.     UBYTE pad_b[2];
  2177.     UBYTE pmi;
  2178.     UBYTE pad_c;
  2179.   } command =
  2180.   {
  2181.     SCSI_CMD_RCP,    /* READ CAPACITY = READ CD-ROM CAPACITY */
  2182.     PAD,        /* LUN | rsrvd. | RelAddr */
  2183.     0,            /* start from sec 0 */
  2184.     PAD, PAD,
  2185.     0,            /* PMI */
  2186.     PAD
  2187.   };
  2188.  
  2189.   int err;
  2190.  
  2191.   if ((err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
  2192.             (UBYTE *) & command, sizeof (command),
  2193.             (SCSIF_READ | SCSIF_AUTOSENSE))) == 0)
  2194.     {
  2195.       if (parsed == TRUE)
  2196.         /* output parsed data */
  2197.         {
  2198.           ULONG sec_no = *((ULONG *) & scsi_data[0]);
  2199.           ULONG sec_size = *((ULONG *) & scsi_data[4]);
  2200.  
  2201.           printf ("Max Sec = %7ld , sec size = %4ld (capacity = %7ld KB)\n",
  2202.                   sec_no, sec_size, (sec_no * sec_size) / 1024);
  2203.         }
  2204.       else
  2205.         /* output raw data */
  2206.         {
  2207.           rawhexasciioutput (scsi_data, 8, 0);
  2208.         }
  2209.     }
  2210.   else
  2211.     {
  2212.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  2213.     }
  2214. }
  2215.  
  2216. /*********************************************************************
  2217.  *
  2218.  *    function to read audio CD TOC (table of contents)
  2219.  *
  2220.  */
  2221.  
  2222. void
  2223. read_toc (int toclong)
  2224. {
  2225.   static IDTOSTRING Qfield[] =
  2226.   {
  2227.     0x00, "Sub-channel Q mode information not supplied.",
  2228.     0x01, "Sub-channel Q encodes current position data.",
  2229.     0x02, "Sub-channel Q encodes media catalog number.",
  2230.     0x03, "Sub-channel Q encodes ISRC.",
  2231.     -1, "Reserved"
  2232.   };
  2233.  
  2234.   static IDTOSTRING Qfieldshort[] =
  2235.   {
  2236.     0x00, "not.suppl.",
  2237.     0x01, "cur.posdt.",
  2238.     0x02, "med.cat.#.",
  2239.     0x03, "ISRC",
  2240.     -1, "reserved"
  2241.   };
  2242.  
  2243.   static SCSICMD10 command =
  2244.   {
  2245.     SCSI_CMD_READTOC,        /* SCSI command read table of contents */
  2246.     0,
  2247.     PAD, PAD, PAD, PAD,
  2248.     0,                /* starting track */
  2249.     0x03, 0x24,            /* max. TOC data length on current CD-ROMs 804 bytes
  2250.                    or 100 TOC track descriptors */
  2251.     PAD
  2252.   };
  2253.  
  2254.   int err, tocsize;
  2255.   UBYTE *tocptr;
  2256.  
  2257.   if ((err = DoScsiCmd ((UBYTE *) toc_buf, MAX_TOC_LEN,
  2258.             (UBYTE *) & command, sizeof (command),
  2259.             (SCSIF_READ | SCSIF_AUTOSENSE))) == 0)
  2260.     {
  2261.       tocsize = (toc_buf[0] << 8) | toc_buf[1];        /* first word encodes length */
  2262.  
  2263.       if (toclong == 0)
  2264.         /* display TOC raw form */
  2265.         {
  2266.           rawhexasciioutput(toc_buf, (toc_buf[0]<<8 | toc_buf[1]), 0);
  2267.         }
  2268.       else if (toclong == 1)
  2269.     /* display TOC short form */
  2270.     {
  2271.           printf ("TOC len: %d\n", tocsize);
  2272.           printf ("First/last track: %d, %d\n", toc_buf[2], toc_buf[3]);
  2273.  
  2274.       if (tocsize >= 2)    /* TOC Data Length - FTN - LTN */
  2275.         tocsize -= 2;
  2276.  
  2277.       for (tocptr = &toc_buf[4]; tocptr < (&toc_buf[4] + tocsize); tocptr += 8)
  2278.         {
  2279.           printf ("#%3.3d: ADR:%10.10s %-15.15s Dig.copy.%5.5s. %-9.9s %cChan. %ld\n",
  2280.               tocptr[2],
  2281.               id2string (((tocptr[1] >> 4) & 0x0F), Qfieldshort),
  2282.               (tocptr[1] & 0x01) ? "pre-emphasis" : "no-pre-emphasis",
  2283.               (tocptr[1] & 0x02) ? "prmtd" : "prohb.",
  2284.               (tocptr[1] & 0x04) ? "Data tr." : "Audio tr.",
  2285.               (tocptr[1] & 0x08) ? '4' : '2',
  2286.               ((tocptr[4] << 24) | (tocptr[5] << 16) | (tocptr[6] << 8) | (tocptr[7]))
  2287.         );
  2288.         }
  2289.     }
  2290.       else if (toclong == 2)
  2291.     /* display TOC long form */
  2292.     {
  2293.           printf ("TOC len: %d\n", tocsize);
  2294.           printf ("First/last track: %d, %d\n", toc_buf[2], toc_buf[3]);
  2295.  
  2296.       if (tocsize >= 2)    /* TOC Data Length - FTN - LTN */
  2297.         tocsize -= 2;
  2298.  
  2299.       for (tocptr = &toc_buf[4]; tocptr < (&toc_buf[4] + tocsize); tocptr += 8)
  2300.         {
  2301.  
  2302.           printf ("Track number: %d\n", tocptr[2]);
  2303.  
  2304.           printf (" ADR: $%lx: %s\n", ((tocptr[1] >> 4) & 0x0F), id2string (((tocptr[1] >> 4) & 0x0F), Qfield));
  2305.  
  2306.           printf (" Audio with%s pre-emphasis.  ", (tocptr[1] & 0x01) ? "" : "out");
  2307.           printf (" Digital copy %s\n", (tocptr[1] & 0x02) ? "permitted" : "prohibited");
  2308.           printf (" %s track.  ", (tocptr[1] & 0x04) ? "Data" : "Audio");
  2309.           printf (" %s channel audio.  ", (tocptr[1] & 0x08) ? "Four" : "Two");
  2310.  
  2311.           printf (" Absolute address: %ld\n", ((tocptr[4] << 24) | (tocptr[5] << 16) | (tocptr[6] << 8) | (tocptr[7])));
  2312.         }
  2313.     }
  2314.       else
  2315.     /* toclong is neither 0,1 or 2 - this should never happen! */
  2316.     {
  2317.       fprintf (stderr, "Error : internal error in read_toc!\n");
  2318.     }
  2319.     }
  2320.   else
  2321.     {
  2322.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  2323.     }
  2324. }
  2325.  
  2326. /*********************************************************************
  2327.  *
  2328.  *    function to play audio
  2329.  *
  2330.  */
  2331.  
  2332. void
  2333. play_audio (int starttrack, int startindex, int endtrack, int endindex)
  2334. {
  2335.   static SCSICMD10 command =
  2336.   {
  2337.     SCSI_CMD_PLAYAUDIOTRACKINDEX,    /* Play audio track */
  2338.     PAD,            /* LUN */
  2339.     PAD,            /* Reserved */
  2340.     PAD,            /* Reserved */
  2341.     0,                /* Starting Track */
  2342.     0,                /* Starting Index */
  2343.     PAD,            /* Reserved */
  2344.     0,                /* Ending Track */
  2345.     0,                /* Ending Index */
  2346.     PAD                /* Control */
  2347.   };
  2348.  
  2349.   int err;
  2350.  
  2351.   command.b4 = starttrack;    /* set audio track to play */
  2352.   command.b5 = startindex;
  2353.   command.b7 = endtrack;    /* ending track */
  2354.   command.b8 = endindex;
  2355.  
  2356.   finddrivebrand ();        /* figure out drivetype */
  2357.  
  2358.   if (whatdrive == APPLECD150)
  2359.     {
  2360.       command.opcode = 0xC9;    /* Apple CD-150 / Pioneer Opcode for playing audio tracks */
  2361.     }
  2362.  
  2363.   if ((err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
  2364.             (UBYTE *) & command, sizeof (command),
  2365.             (SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
  2366.     {
  2367.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  2368.     }
  2369. }
  2370.  
  2371. /*********************************************************************
  2372.  *
  2373.  *    function to compare two binary strings
  2374.  *
  2375.  *    returns FALSE if different
  2376.  */
  2377.  
  2378. int
  2379. gcomp (char *p1, char *p2, int len)
  2380. {
  2381.   while (len--)
  2382.     {
  2383.       if (*p1++ != *p2++)
  2384.     return (FALSE);
  2385.     }
  2386.   return (TRUE);
  2387. }
  2388.  
  2389. /*********************************************************************
  2390.  *
  2391.  * searches DeviceList for a device name with a given string in it.
  2392.  * - if found returns with a pointer to it, else NULL
  2393.  */
  2394.  
  2395. extern struct ExecBase *SysBase;
  2396.  
  2397. UBYTE *
  2398. GetDevName (char *grep)
  2399. {
  2400.   LIST *lh = (LIST *) SysBase->DeviceList.lh_Head;
  2401.   NODE *ln;
  2402.  
  2403.   for (ln = lh->lh_Head; ln->ln_Succ; ln = ln->ln_Succ)
  2404.     {
  2405.       UBYTE *p = ln->ln_Name;
  2406.  
  2407.       while (*p != '.')
  2408.     {
  2409.       if (strncmp (p, grep, 4) == 0)
  2410.         {
  2411.           return (ln->ln_Name);
  2412.         }
  2413.       ++p;
  2414.     }
  2415.     }
  2416.  
  2417.   return (NULL);        /* not found */
  2418. }
  2419.  
  2420. /*********************************************************************
  2421.  *
  2422.  *    Break (^C) function
  2423.  *
  2424.  */
  2425.  
  2426. int
  2427. breakcheck (void)
  2428. {
  2429.   int zz = SetSignal (0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C;
  2430.   if (zz)
  2431.     {
  2432.       fprintf (stderr, "\n***BREAK: ^C\n");
  2433.     }
  2434.   return (zz);
  2435. }
  2436.  
  2437. #ifdef __SASC
  2438. /*********************************************************************
  2439.  *
  2440.  *  tell SAS to turn of CTRL-C checking
  2441.  */
  2442. void __regargs
  2443. __chkabort (void)
  2444. {
  2445. }
  2446.  
  2447. #endif
  2448.  
  2449. /*********************************************************************
  2450.  *
  2451.  *    function to send a scsi command (uses asynchronous I/O)
  2452.  *
  2453.  */
  2454. void
  2455. SendScsiCmd (int req, UBYTE * data, int datasize, UBYTE * cmd, int cmdsize, UBYTE flags)
  2456. {
  2457.  
  2458.   io_ptr[req]->io_Length = sizeof (SCSICMD);
  2459.   io_ptr[req]->io_Data = (APTR) & scsi_cmd[req];
  2460.   io_ptr[req]->io_Command = HD_SCSICMD;
  2461.  
  2462.   scsi_cmd[req].scsi_Data = (APTR) data;
  2463.   scsi_cmd[req].scsi_Length = datasize;
  2464.   scsi_cmd[req].scsi_SenseActual = 0;
  2465.   scsi_cmd[req].scsi_SenseData = scsi_sense[req];
  2466.   scsi_cmd[req].scsi_SenseLength = SENSE_LEN;
  2467.   scsi_cmd[req].scsi_Command = cmd;
  2468.   scsi_cmd[req].scsi_CmdLength = cmdsize;
  2469.   scsi_cmd[req].scsi_Flags = flags;
  2470.  
  2471.   (void) SendIO ((struct IORequest *) io_ptr[req]);
  2472.  
  2473. }
  2474.  
  2475. /*********************************************************************
  2476.  *
  2477.  *    function to wait for an asynchronous scsi command
  2478.  *
  2479.  */
  2480. int
  2481. WaitScsiCmd (int req)
  2482. {
  2483.   int i;
  2484.  
  2485.   WaitIO ((struct IORequest *) io_ptr[req]);
  2486.  
  2487.   if (scsi_cmd[req].scsi_SenseActual)
  2488.     {
  2489.       fprintf (stderr, "SENSE_DATA:");
  2490.       for (i = 0; i < scsi_cmd[req].scsi_SenseActual; i++)
  2491.     {
  2492.       fprintf (stderr, " %02x", scsi_cmd[req].scsi_SenseData[i]);
  2493.     }
  2494.       fprintf (stderr, "\n");
  2495.     }
  2496.   return (io_ptr[req]->io_Error);
  2497. }
  2498.  
  2499. /*********************************************************************
  2500.  *
  2501.  *    function to use a scsi command
  2502.  *
  2503.  */
  2504. int
  2505. DoScsiCmd (UBYTE * data, int datasize, UBYTE * cmd, int cmdsize, UBYTE flags)
  2506. {
  2507.   int i;
  2508.  
  2509.   io_ptr[0]->io_Length = sizeof (SCSICMD);
  2510.   io_ptr[0]->io_Data = (APTR) & scsi_cmd[0];
  2511.   io_ptr[0]->io_Command = HD_SCSICMD;
  2512.  
  2513.   scsi_cmd[0].scsi_Data = (APTR) data;
  2514.   scsi_cmd[0].scsi_Length = datasize;
  2515.   scsi_cmd[0].scsi_SenseActual = 0;
  2516.   scsi_cmd[0].scsi_SenseData = scsi_sense[0];
  2517.   scsi_cmd[0].scsi_SenseLength = SENSE_LEN;
  2518.   scsi_cmd[0].scsi_Command = cmd;
  2519.   scsi_cmd[0].scsi_CmdLength = cmdsize;
  2520.   scsi_cmd[0].scsi_Flags = flags;
  2521.  
  2522.   (void) DoIO ((struct IORequest *) io_ptr[0]);
  2523.  
  2524.   if (scsi_cmd[0].scsi_SenseActual)
  2525.     {
  2526.       fprintf (stderr, "SENSE_DATA:");
  2527.       for (i = 0; i < scsi_cmd[0].scsi_SenseActual; i++)
  2528.     {
  2529.       fprintf (stderr, " %02x", scsi_cmd[0].scsi_SenseData[i]);
  2530.     }
  2531.       fprintf (stderr, "\n");
  2532.     }
  2533.   return (io_ptr[0]->io_Error);
  2534. }
  2535.  
  2536. /*********************************************************************
  2537.  *
  2538.  *    function to return an error string
  2539.  *
  2540.  *
  2541.  */
  2542.  
  2543. UBYTE *
  2544. err_str (int err)
  2545. {
  2546.  
  2547.   static UBYTE *errors[] =
  2548.   {
  2549.     " cannot issue SCSI command to self ",
  2550.     " DMA error ",
  2551.     " illegal or unexpected SCSI phase ",
  2552.     " SCSI parity error ",
  2553.     " Select timed out ",
  2554.     " status and/or sense error "
  2555.   };
  2556.  
  2557.   err -= 40;
  2558.  
  2559.   if ((err < 0) || (err > 5))
  2560.     return ("Error out-of-range");
  2561.   else
  2562.     return (errors[err]);
  2563. }
  2564.  
  2565. /*********************************************************************
  2566.  *
  2567.  *    usage function
  2568.  *
  2569.  *
  2570.  */
  2571.  
  2572. void
  2573. usage (void)
  2574. {
  2575.   static char *zz[] =
  2576.   {
  2577.     "Usage: SCSIutil [-dscsi_dev] <scsi_id> <command>\n",
  2578.     " -c[r]                 : Read capacity [raw]\n",
  2579.     " -d<l|r|s> sec blks sc : Read 16 bit digital audio(start sector/# blocks)(2)\n",
  2580.     " -D<l|r> sec blks      : Read  8 bit digital audio(left or right channel)(3)\n",
  2581.     " -e <0|1>              : Change medium (0=eject, 1=load)\n",
  2582.     " -i[r]                 : Inquiry [raw]\n",
  2583.     " -h[r] blk             : Read CD-ROM data block address header\n",
  2584.     " -l <0|1>              : Allow/Prevent medium removal\n",
  2585.     " -m <0|1>              : Stop/Start motor {0=stop, 1=start}\n",
  2586.     " -o[r] contr page      : Mode sense (contr = 0-3))\n",
  2587.     " -p st si et ei        : Play audio CD track (1-99), index (1-99)\n",
  2588.     " -r[t] sec_no          : Read sectors [use trackdisk.device]\n",
  2589.     " -s sec_no             : Seek to sector (5)\n",
  2590.     " -t[r|l]               : Display TOC of an audio CD [raw|long]\n",
  2591.     " -u[r] chan fmt track  : Read CD sub-channel information [raw] (6)\n",
  2592.     " -v [vl0 vl1 vl2 vl3]  : Set output volume channels 0-3 (7)\n",
  2593. #ifdef USE8SVX
  2594.     " -8<l|r|s> sec blks   : Read digital audio -> 8SVX (left, right or stereo) (7)\n",
  2595. #endif    /* USE8SVX */
  2596.     "\n",
  2597.     "Note 1: usually scsi_id = (BOARD * 100) + (LUN * 10) + SCSI_TARGET_ID\n",
  2598.     "     2: with 's' returns LRLRLR pairs of stereo audio, 2352 bytes per block\n",
  2599.     "        sc = Apple subcode (0=2352, 1=2368, 2=2448, 3=96 byte/block)\n",
  2600.     "     3: converted to 8 bit audio (-d and -D work with Sony CDU 561 & 8003)\n",
  2601.     "     4: contr 0: current, 1: changeable, 2: default, 3: saved values\n",
  2602.     "     5: to park heads, try sec_no of -1\n",
  2603.     "     6: Q-channel = 64, fmt: 0=Sub-Q Channel data,1=current CD-ROM pos.,\n",
  2604.     "        2=Media Catalog Number (UPC/Bar Code),3=Track ISRC\n",
  2605.     "     7: use -1 to leave volume of channel as it is, without argument shows\n",
  2606.     "        current volume settings\n",
  2607. #ifdef USE8SVX
  2608.     "     8: output 8SVX IFF (in case of stereo needs to read the CD twice)\n",
  2609. #endif    /* USE8SVX */
  2610.     ""                /* TERM */
  2611.   };
  2612.  
  2613.   int j = 0;
  2614.  
  2615.   fprintf (stderr, "SCSIutil V%s [%s : %s] - written by Gary Duncan\n",
  2616.        VERSION, __DATE__, __TIME__, pname);
  2617.   fprintf (stderr, "         (gduncan@philips.oz.au) and Heiko Rath (hr@brewhr.swb.de)\n");
  2618.  
  2619.   while (*zz[j++])
  2620.     fprintf (stderr, "%s", zz[j - 1]);
  2621. }
  2622.  
  2623. /*********************************************************************
  2624.  *
  2625.  *    sense_errs function ; prints sense errors
  2626.  *
  2627.  *
  2628.  */
  2629.  
  2630. UBYTE *
  2631. sense_errs (int req, int err)
  2632. {
  2633.   typedef struct
  2634.   {
  2635.     BYTE code;
  2636.     BYTE sense;
  2637.     UBYTE *ptr;
  2638.   } S_ERRS;
  2639.  
  2640. /*
  2641.  *    only the likely, interesting ones filled in, e.g media errors
  2642.  */
  2643.   static S_ERRS x[] =
  2644.   {
  2645.     0x00, 0x00, "No error",
  2646.     0x01, 0x04, "?",
  2647.     0x02, 0x04, "?",
  2648.     0x03, 0x04, "?",
  2649.     0x04, 0x02, "?",
  2650.     0x06, 0x04, "?",
  2651.     0x09, 0x04, "?",
  2652.     0x10, 0x03, "?",
  2653.     0x10, 0x04, "?",
  2654.     0x11, 0x03, "?",
  2655.     0x12, 0x03, "?",
  2656.     0x13, 0x03, "?",
  2657.     0x14, 0x03, "?",
  2658.     0x15, 0x04, "Seek error ",
  2659.     0x17, 0x01, "?",
  2660.     0x18, 0x01, "?",
  2661.     0x19, 0x03, "?",
  2662.     0x1A, 0x05, "?",
  2663.     0x20, 0x05, "Invalid command op code",
  2664.     0x21, 0x05, "Illegal sector address",
  2665.     0x24, 0x05, "?",
  2666.     0x25, 0x05, "Invalid LUN",
  2667.     0x26, 0x05, "Invalid field in parameter list",
  2668.     0x29, 0x06, "?",
  2669.     0x2A, 0x06, "?",
  2670.     0x31, 0x03, "?",
  2671.     0x32, 0x01, "?",
  2672.     0x32, 0x03, "?",
  2673.     0x40, 0x04, "?",
  2674.     0x41, 0x04, "?",
  2675.     0x42, 0x04, "Power-on diagnostic failure",
  2676.     0x43, 0x04, "?",
  2677.     0x45, 0x04, "Select / reselect failure ",
  2678.     0x47, 0x04, "SCSI Interface Parity Error",
  2679.     0x48, 0x0B, "?",
  2680.     0x49, 0x0B, "Illegal message drive can't support",
  2681.     -1, -1, "ILLEGAL sense!!"
  2682.   };
  2683.  
  2684.   int j = 0;
  2685.   UBYTE *p;
  2686.   char sense;
  2687.   char code;
  2688.  
  2689.   /*
  2690.    *    verify that sense data looks valid
  2691.    */
  2692.   if (((scsi_cmd[req].scsi_Status & 2) == 0) ||
  2693.       (scsi_cmd[req].scsi_SenseActual < OFFS_KEY))
  2694.     {
  2695.       return ("");
  2696.     }
  2697.   sense = scsi_cmd[req].scsi_SenseData[OFFS_KEY] & 0xF;
  2698.   code = scsi_cmd[req].scsi_SenseData[OFFS_CODE];
  2699.  
  2700.   do
  2701.     {
  2702.       p = x[j].ptr;
  2703.       if ((x[j].code == code) && (x[j].sense == sense))
  2704.     break;
  2705.   } while (x[j++].code != -1);
  2706.  
  2707.   return (p);
  2708. }
  2709.  
  2710. /*********************************************************************
  2711.  *
  2712.  *    id2string function ; return pointer to string for matching id
  2713.  *
  2714.  */
  2715.  
  2716. UBYTE *
  2717. id2string (int id, IDTOSTRING * idtable)
  2718. {
  2719.   int j = 0;
  2720.   UBYTE *p;
  2721.  
  2722.   do
  2723.     {
  2724.       p = idtable[j].ptr;
  2725.       if (idtable[j].code == id)
  2726.     break;
  2727.   } while (idtable[j++].code != -1);
  2728.   return p;
  2729. }
  2730.